Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions TODOS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# TODOs

## CI/CD pipeline for integration packages

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this file seems unnecessary


**What:** Add GitHub Actions workflows to build, test, and publish `strands-agents-moss` and `semantic-kernel-moss` to PyPI.

**Why:** Neither integration package has a CI/CD pipeline. Code without distribution is code nobody can use. Users currently have no way to `pip install` these packages from PyPI.

**Context:** Both packages use setuptools with `pyproject.toml`. Tests use pytest + pytest-asyncio. Linting uses ruff. A single reusable workflow could cover both packages since they share the same build system and test tooling. Consider matrix strategy for Python 3.10-3.13.

**Depends on:** Nothing. Can be done independently.

## .NET Semantic Kernel plugin design doc

**What:** Write a design document for a .NET version of the Moss Semantic Kernel plugin.

**Why:** The GitHub issue (#82) lists .NET as a stretch goal. Semantic Kernel has strong .NET adoption in enterprise shops. A design doc captures the approach (NuGet package, IKernelPlugin interface, C# async patterns) without committing to implementation.

**Context:** The Python plugin (`semantic-kernel-moss`) is the reference implementation. The .NET version would follow the same pattern: single `Search` kernel function, constructor-configured `MossClient`, pre-loaded index. Key decisions: whether to use the .NET Moss SDK (if it exists) or wrap the Python SDK, and how to handle the async index loading lifecycle in C#.

**Depends on:** Python plugin shipped and validated by users.
25 changes: 25 additions & 0 deletions packages/semantic-kernel-moss/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
BSD 2-Clause License

Copyright (c) 2025, InferEdge Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
98 changes: 98 additions & 0 deletions packages/semantic-kernel-moss/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Semantic Kernel Moss Plugin

Moss delivers sub-10ms semantic retrieval, giving your [Semantic Kernel](https://learn.microsoft.com/en-us/semantic-kernel/) agents instant access to a knowledge base during conversations.

## Installation

```bash
pip install semantic-kernel-moss
```

## Prerequisites

- Moss project ID and project key (get them from [Moss Portal](https://portal.usemoss.dev))
- Python 3.10+
- A Semantic Kernel [ChatCompletion service](https://learn.microsoft.com/en-us/semantic-kernel/concepts/ai-services/chat-completion/) configured in your kernel

## Quick Start

```python
import asyncio
import os

import semantic_kernel as sk
from semantic_kernel_moss import MossPlugin


async def main():
# Create and pre-load the Moss plugin
moss = MossPlugin(
project_id=os.getenv("MOSS_PROJECT_ID"),
project_key=os.getenv("MOSS_PROJECT_KEY"),
index_name="my-index",
)
await moss.load_index()

# Register with a Semantic Kernel
kernel = sk.Kernel()
kernel.add_plugin(moss, plugin_name="moss")

# Invoke the search function directly
result = await kernel.invoke(function_name="search", plugin_name="moss", query="What is your refund policy?")
print(result)


asyncio.run(main())
```

## Configuration Options

### MossPlugin

| Parameter | Default | Description |
|-----------|---------|-------------|
| `project_id` | `MOSS_PROJECT_ID` env var | Moss project ID |
| `project_key` | `MOSS_PROJECT_KEY` env var | Moss project key |
| `index_name` | (required) | Name of the Moss index to query |
| `top_k` | `5` | Number of results to retrieve per query |
| `alpha` | `0.8` | Blend: 1.0 = semantic only, 0.0 = keyword only |
| `result_prefix` | `Relevant knowledge base results:\n\n` | Prefix for formatted results |

### Methods

| Method | Description |
|--------|-------------|
| `load_index()` | Async. Pre-load the Moss index for fast first queries |
| `search(query)` | Async. Query Moss and return formatted results as a string |

## Using with Chat Completion

Moss works with any Semantic Kernel chat completion service. The kernel can automatically invoke the search function when the LLM decides it needs knowledge base information:

```python
import semantic_kernel as sk
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
from semantic_kernel_moss import MossPlugin

kernel = sk.Kernel()
kernel.add_service(OpenAIChatCompletion(service_id="chat"))

moss = MossPlugin(index_name="product-docs")
await moss.load_index()
kernel.add_plugin(moss, plugin_name="moss")

result = await kernel.invoke_prompt(
"Use the moss-search function to answer: {{$input}}",
input_vars={"input": "What are your shipping options?"},
)
```

## License

This plugin is provided under the [BSD 2-Clause License](LICENSE).

## Support

- [Moss Docs](https://docs.moss.dev)
- [Moss Discord](https://discord.com/invite/eMXExuafBR)
- [Semantic Kernel Docs](https://learn.microsoft.com/en-us/semantic-kernel/)
28 changes: 28 additions & 0 deletions packages/semantic-kernel-moss/examples/moss_sk_simple.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""Minimal demo: Moss semantic search with a Semantic Kernel agent."""

import asyncio
import os

import semantic_kernel as sk

from semantic_kernel_moss import MossPlugin


async def main():
"""Run a Semantic Kernel agent with Moss semantic search."""
moss = MossPlugin(
project_id=os.getenv("MOSS_PROJECT_ID"),
project_key=os.getenv("MOSS_PROJECT_KEY"),
index_name=os.getenv("MOSS_INDEX_NAME", "my-index"),
Comment on lines +13 to +16

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add .env.example

)
await moss.load_index()

kernel = sk.Kernel()
kernel.add_plugin(moss, plugin_name="moss")

result = await kernel.invoke(function_name="search", plugin_name="moss", query="What are your shipping options?")
print(result)


if __name__ == "__main__":
asyncio.run(main())
55 changes: 55 additions & 0 deletions packages/semantic-kernel-moss/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
[project]
name = "semantic-kernel-moss"
version = "0.0.1"
description = "Moss semantic search plugin for Semantic Kernel"
readme = "README.md"
requires-python = ">=3.10,<3.14"
dependencies = [
"moss>=1.0.0b18",
"semantic-kernel>=1.0.0",
]

[dependency-groups]
dev = [
"pytest>=7.0",
"pytest-asyncio>=0.21",
"python-dotenv>=1.2.1",
"ruff>=0.1.0",
]

[tool.ruff]
line-length = 100
target-version = "py310"

[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear
"UP", # pyupgrade
"D", # pydocstyle
]
ignore = [
"D100", # Missing docstring in public module
"D104", # Missing docstring in public package
]

[tool.ruff.lint.pydocstyle]
convention = "google"

[tool.ruff.format]
quote-style = "double"
indent-style = "space"
skip-magic-trailing-comma = false
line-ending = "auto"

[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"


[tool.setuptools.packages.find]
where = ["src"]
namespaces = false
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""Moss semantic search plugin for Semantic Kernel."""

from __future__ import annotations

from moss import (
DocumentInfo,
GetDocumentsOptions,
IndexInfo,
MossClient,
SearchResult,
)

from .moss_plugin import MossPlugin

__all__ = [
"DocumentInfo",
"GetDocumentsOptions",
"IndexInfo",
"MossClient",
"MossPlugin",
"SearchResult",
]
Loading
Loading