Refactored orchestrator for staged file handling, added structured prompt support, adjusted Feishu file handling
This commit is contained in:
Vendored
+3
@@ -6,6 +6,7 @@
|
|||||||
"type": "go",
|
"type": "go",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"mode": "auto",
|
"mode": "auto",
|
||||||
|
"preLaunchTask": "Kill Stale LaodingBot Debug Processes",
|
||||||
"program": "${workspaceFolder}/cmd/bot",
|
"program": "${workspaceFolder}/cmd/bot",
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
"envFile": "${workspaceFolder}/configs/env"
|
"envFile": "${workspaceFolder}/configs/env"
|
||||||
@@ -15,6 +16,7 @@
|
|||||||
"type": "go",
|
"type": "go",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"mode": "auto",
|
"mode": "auto",
|
||||||
|
"preLaunchTask": "Kill Stale LaodingBot Debug Processes",
|
||||||
"program": "${workspaceFolder}/cmd/bot",
|
"program": "${workspaceFolder}/cmd/bot",
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
"envFile": "${workspaceFolder}/configs/env",
|
"envFile": "${workspaceFolder}/configs/env",
|
||||||
@@ -27,6 +29,7 @@
|
|||||||
"type": "go",
|
"type": "go",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"mode": "auto",
|
"mode": "auto",
|
||||||
|
"preLaunchTask": "Kill Stale LaodingBot Debug Processes",
|
||||||
"program": "${workspaceFolder}/cmd/bot",
|
"program": "${workspaceFolder}/cmd/bot",
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
"envFile": "${workspaceFolder}/configs/env",
|
"envFile": "${workspaceFolder}/configs/env",
|
||||||
|
|||||||
Vendored
+11
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "Kill Stale LaodingBot Debug Processes",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "pkill -f '/LaodingBot/cmd/bot/__debug_bin|dlv.*LaodingBot/cmd/bot|dlv dap' || true",
|
||||||
|
"problemMatcher": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ Go-based personal Telegram Agent with:
|
|||||||
- Telegram polling transport
|
- Telegram polling transport
|
||||||
- OpenAI-compatible LLM client
|
- OpenAI-compatible LLM client
|
||||||
- SQLite conversation memory + simple compression
|
- SQLite conversation memory + simple compression
|
||||||
- Tool registry with built-in `file` and `shell` tools
|
- Tool registry with built-in `file`, `shell`, and `git` tools
|
||||||
- Default-deny security policy via allowlists
|
- Default-deny security policy via allowlists
|
||||||
- Soul markdown loading for bot personality
|
- Soul markdown loading for bot personality
|
||||||
- Skills markdown loading for capability context
|
- Skills markdown loading for capability context
|
||||||
@@ -50,7 +50,7 @@ go run ./cmd/bot
|
|||||||
1. Receive message and load recent memory context
|
1. Receive message and load recent memory context
|
||||||
2. Match relevant skill(s) from `skills/`
|
2. Match relevant skill(s) from `skills/`
|
||||||
3. If no skill matched, respond via direct LLM
|
3. If no skill matched, respond via direct LLM
|
||||||
4. If skill matched, run ReAct and call tools (`shell` / `file`) only when needed
|
4. If skill matched, run ReAct and call tools (`shell` / `file` / `git`) only when needed
|
||||||
5. Return final answer
|
5. Return final answer
|
||||||
- No `/tool ...` command is required for normal use.
|
- No `/tool ...` command is required for normal use.
|
||||||
|
|
||||||
@@ -69,6 +69,7 @@ go run ./cmd/bot
|
|||||||
|
|
||||||
- `shell` only allows commands listed in `ALLOWED_COMMANDS`.
|
- `shell` only allows commands listed in `ALLOWED_COMMANDS`.
|
||||||
- `file` only allows paths inside `ALLOWED_DIRS`.
|
- `file` only allows paths inside `ALLOWED_DIRS`.
|
||||||
|
- `git` only allows common git subcommands and runs inside `WORK_DIR`.
|
||||||
- Working directory for shell is limited by `WORK_DIR`.
|
- Working directory for shell is limited by `WORK_DIR`.
|
||||||
|
|
||||||
## Next Iteration
|
## Next Iteration
|
||||||
|
|||||||
@@ -177,6 +177,24 @@ func runMessageChannel(ctx context.Context, cfg config.Config, engine *agent.Orc
|
|||||||
}
|
}
|
||||||
lg.Infof("starting feishu transport")
|
lg.Infof("starting feishu transport")
|
||||||
return fs.Run(ctx, func(ctx context.Context, msg feishu.IncomingMessage) (string, error) {
|
return fs.Run(ctx, func(ctx context.Context, msg feishu.IncomingMessage) (string, error) {
|
||||||
|
if msg.MsgType == "file" && len(msg.FileBytes) > 0 {
|
||||||
|
content := msg.FileBytes
|
||||||
|
if msg.FilePath != "" {
|
||||||
|
if b, err := os.ReadFile(msg.FilePath); err == nil && len(b) > 0 {
|
||||||
|
content = b
|
||||||
|
} else if lg != nil {
|
||||||
|
lg.Warnf("read local file failed path=%s err=%v; fallback to in-memory bytes", msg.FilePath, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
files := []llm.InputFile{{
|
||||||
|
FileName: msg.FileName,
|
||||||
|
MimeType: msg.FileMime,
|
||||||
|
Content: content,
|
||||||
|
}}
|
||||||
|
// Feishu file event and user question are split into separate messages.
|
||||||
|
// Use empty text so file IDs are cached and consumed by the next text query.
|
||||||
|
return engine.HandleMessageWithFiles(ctx, msg.ChatID, msg.UserID, "", files)
|
||||||
|
}
|
||||||
return engine.HandleMessage(ctx, msg.ChatID, msg.UserID, msg.Text)
|
return engine.HandleMessage(ctx, msg.ChatID, msg.UserID, msg.Text)
|
||||||
})
|
})
|
||||||
default:
|
default:
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,250 @@
|
|||||||
|
|
||||||
|
|
||||||
|
Sub-Goal 5: User’s experience is
|
||||||
|
enhanced by the provision of Use Cases: 3 Requirements: 8
|
||||||
|
value-added services
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Figure 2 Structure of this document.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
1.6 Product Scope and Perspective
|
||||||
|
The EIP Project’s urban platform is an open common architecture which serves for city data
|
||||||
|
collection, management and distribution. An urban platform is intended to support the widespread
|
||||||
|
exploitation of city data by humans and machines in the urban environment. Figure 3 illustrates a
|
||||||
|
holistic high level overview of the urban platform the EIP project intends to deliver.
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 6
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
The reference architecture for urban platforms should:
|
||||||
|
|
||||||
|
• Cater for interoperability between urban infrastructures
|
||||||
|
• Enable replicability of the solutions/platforms city to city
|
||||||
|
• Scale without technical constraints and excessive cost increase
|
||||||
|
• Provide open APIs and SDKs
|
||||||
|
• Enable Real Time capabilities
|
||||||
|
• Support implementation of functional and technical capabilities
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Figure 3. High level overview of the urban platform (currently approved EC DG CNECT).
|
||||||
|
|
||||||
|
|
||||||
|
The current urban platform market is nascent. Many software vendors offer such a platform, though
|
||||||
|
many requirements and expectations of the stakeholders of city data are not (fully) addressed. As
|
||||||
|
a result, current urban platforms are often more costly to design and maintain, less reusable and
|
||||||
|
often not interoperable platform-to-platform, and susceptible to information fragmentation and
|
||||||
|
overload.
|
||||||
|
|
||||||
|
The urban platform which the EIP initiative intends to design takes a step beyond the platforms
|
||||||
|
currently on the market by ensuring the requirements are fully founded on a co-created and
|
||||||
|
common set of representative city needs, from which it solicits suitable industry input, and an open
|
||||||
|
and managed collaboration between industry, cities and communities, and others, in order to take
|
||||||
|
into account their needs and concerns. To do this, it is necessary to take a technology agnostic
|
||||||
|
approach to design an open and common reference architecture for urban platforms. This platform
|
||||||
|
must ensure data is collected and sustained in accordance with well-stablished standards,
|
||||||
|
managed in a robust manner so that it can handle high level supply and demand of data, and
|
||||||
|
distributed across different value chains, systems and stakeholders. The ability to handle high level
|
||||||
|
of city data supply and demand while being user secure and accessible enough for city-wide
|
||||||
|
exploitation of data is one of many keys to the success of urban platforms. This is central to the
|
||||||
|
design and implementation of urban platforms.
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 7
|
||||||
|
|
||||||
|
|
||||||
|
1.7 The Urban Platform Development Stack
|
||||||
|
The requirements specification of this document is based on the Urban Platform Development
|
||||||
|
Stack illustrated in Figure 4. The stack is composed by five domains (represented as layers in the
|
||||||
|
stack) necessary to fully implement an urban platform software suite as shown in Table 1. Each
|
||||||
|
domain comprehends a set of requirements necessary to the design of a common and open urban
|
||||||
|
data service platform. The elicited requirements are used to define a technical architecture which is
|
||||||
|
simple enough to be comprehensible at least at a high level of abstraction. The platform should be
|
||||||
|
conceptually decomposable into its major subsystems, the platform’s functionality reused by many
|
||||||
|
services and external applications should be identifiable, and interactions between the platform
|
||||||
|
and services, data providers and data consumers should be well defined and explicit.
|
||||||
|
|
||||||
|
The first layer of the stack “Societal needs” concerns to outcomes we strive for within a portfolio of
|
||||||
|
city service domains. An urban platform should recognise societal needs and wants as the starting
|
||||||
|
point for city data service offering. Ultimately, an urban platform aims to provide tailor made and
|
||||||
|
compelling engaging services for the users. The Services and Business models layers concerns
|
||||||
|
with delivering data services which carefully targets the needs and expectations of the different
|
||||||
|
users of the urban platform, and explore use cases and commercial models where data is used to
|
||||||
|
deliver different forms of value. The city data layer concerns with the mechanisms necessary to
|
||||||
|
transform urban platforms into a foundation for widespread exploitation of data, including handling
|
||||||
|
data architectural features, data usability, semantics and quality aspects. The urban platform layer
|
||||||
|
concerns to the technology foundation to configure, share, and interpret exponentially increasing
|
||||||
|
volumes city data and services. Finally, the Infrastructure layer concerns with the base level
|
||||||
|
connectivity that supports the platform to be scalable and reliable in the long run.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
STACK OUTPUT
|
||||||
|
|
||||||
|
Requirements to deliver new digital services that will address the
|
||||||
|
Societal Needs societal needs of cities in a positive manner that relates to political
|
||||||
|
narratives.
|
||||||
|
|
||||||
|
|
||||||
|
Services & Requirements to new profitable business models and the development
|
||||||
|
Business Models of an increase range of new and engaging services in the smart cities.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
City Data Requirements to provide all city data stakeholders ready access and
|
||||||
|
delivery of all city data that unpins the decision making process in smart
|
||||||
|
cities.
|
||||||
|
|
||||||
|
|
||||||
|
Urban Platform Requirements to put in place applications together to build a foundation
|
||||||
|
for the widespread exploitation of data.
|
||||||
|
|
||||||
|
|
||||||
|
Infrastructure Requirements to deliver the backbone infrastructure that will be used to
|
||||||
|
capture the opportunities of digital technology and data to enable
|
||||||
|
transformation.
|
||||||
|
|
||||||
|
|
||||||
|
Figure 4. Urban Platform Development Stack.
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 8
|
||||||
|
|
||||||
|
|
||||||
|
Table 1. Urban Platform Development Stack
|
||||||
|
Layer Rationale
|
||||||
|
Societal Needs - Accessible services and data necessary to solve social problems
|
||||||
|
and drive innovation;
|
||||||
|
- Parameters that influence user’s experience while interacting with
|
||||||
|
services (e.g. usability, feeling of security and trust);
|
||||||
|
Services and Business - Tailor-made data services which careful targets the needs of users
|
||||||
|
Models and businesses;
|
||||||
|
- New potential and cost-effective beneficial services that could be
|
||||||
|
rolled out across cities of different sizes;
|
||||||
|
- Use cases where data is used to deliver different forms of value.
|
||||||
|
City Data - Data architectural features (e.g. volume, variety, temporal factors
|
||||||
|
and sensitivity);
|
||||||
|
- Data licensing, policies and regulations to exploit data to full effect;
|
||||||
|
- Minimum metadata requirements;
|
||||||
|
- Data usability and reusability aspects of humans and machines.
|
||||||
|
Urban Platform - Holistic and interoperable solutions;
|
||||||
|
- Integrated approaches which ensures that services fit together and
|
||||||
|
that synergies can be exploited;
|
||||||
|
- Data management mechanisms to ensure data integrity and
|
||||||
|
compliance with data protection regulations
|
||||||
|
- Extension capabilities to accommodate additional functionality at
|
||||||
|
later stage at a fair and transparent cost.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
1.8 User Classes, Characteristics, and User Access
|
||||||
|
The users of the Urban Platform include end-users, such as the general Public, public and private
|
||||||
|
organisations; data providers; service providers; and the platform providers who will be
|
||||||
|
working with the providers of city data and services, and managing the content, defining policies
|
||||||
|
and regulations of the platform. A crucial feature of an urban platform is the provision of the
|
||||||
|
various access levels required by the different types of users. Particular uses need different
|
||||||
|
access levels to some data than the general public. Data publishers will require access to the
|
||||||
|
Urban Platform in order to ingest, administer, manage, preserve and access their resources. This
|
||||||
|
will require multiple levels of access to city data and its respective metadata. Table 2 provides a
|
||||||
|
description of each class of users.
|
||||||
|
|
||||||
|
|
||||||
|
Table 2. Actors
|
||||||
|
User Class Rationale
|
||||||
|
Platform - Maintains the ecosystem of data, services and users;
|
||||||
|
Provider - Defines standards, licenses and regulations and provides terms and conditions
|
||||||
|
for platform usage and the commercial exploitation of data and services;
|
||||||
|
- Decides who are allowed to join the value network of data and services
|
||||||
|
providers;
|
||||||
|
City Data - Publishes open and proprietary data into the platform;
|
||||||
|
Publisher - Manages and maintain resources in the platform accordingly to terms and
|
||||||
|
conditions.
|
||||||
|
Data - Deploys open and commercial data services into the platform (e.g. data
|
||||||
|
Services visualisation, data cleansing, data integration tools);
|
||||||
|
Provider - Manages and maintain resources in the platform accordingly to terms and
|
||||||
|
conditions.
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 9
|
||||||
|
|
||||||
|
|
||||||
|
City Data - Consumes open and proprietary data provided in the platform;
|
||||||
|
Consumer - Uses open and commercial data services provided in the platform;
|
||||||
|
- Provides feedback on data and services provision;
|
||||||
|
|
||||||
|
|
||||||
|
1.8.1 End-User Access
|
||||||
|
|
||||||
|
City data consumers will need to access and use the city data residing in the Urban Platform. End-
|
||||||
|
users will be able to search metadata and full text within datasets (when available), and obtain city
|
||||||
|
data in open formats readily available to both humans and machines such as CSV, XML, JSON.
|
||||||
|
Some end-users may require different access rights to city data. The 2 major end-user groups that
|
||||||
|
have been identified are:
|
||||||
|
|
||||||
|
• Open data users, including both national and international users (humans and machines).
|
||||||
|
Open access to some city data may be restricted by licensing terms (e.g. commercial data),
|
||||||
|
embargo periods, copyright, etc.
|
||||||
|
|
||||||
|
• Private data users, which need to use the Urban Platform to obtain commercial city data. Data
|
||||||
|
access is available via data subscriptions or when purchase requirements and licenses are
|
||||||
|
waived by the data provider.
|
||||||
|
|
||||||
|
|
||||||
|
1.8.2 City Data Publisher Access
|
||||||
|
|
||||||
|
A broad data provider level access is needed for stakeholders (humans and machines) working
|
||||||
|
with the urban platform and their respective data in it. Basically, data publishers will carry out the
|
||||||
|
following activities:
|
||||||
|
• Data publication access, available to publishers adding new data and metadata, checking the
|
||||||
|
quality of datasets, manipulating data, performing format conversions, defining data-access
|
||||||
|
level, tariff for consumption when applicable, and licences.
|
||||||
|
|
||||||
|
• Data maintenance access, for publishers reviewing or editing appropriate data and metadata in
|
||||||
|
the urban platform. Data publishers can view data and add to or edit metadata without
|
||||||
|
changing the data itself. They should be provided with access to feedback from users to
|
||||||
|
investigate problem in their resources (e.g. missing data, inconsistent metadata), and statistical
|
||||||
|
information about how their resources are used by users.
|
||||||
|
|
||||||
|
|
||||||
|
1.8.3 Data Services Provider Access
|
||||||
|
|
||||||
|
This is the second most restrictive access level providing rights to deploy services in the platform.
|
||||||
|
Basically, data service providers will carry out the following activities:
|
||||||
|
|
||||||
|
• Data services deployment access, available to service providers adding new mechanisms or
|
||||||
|
integrating new applications, testing and validating integration, defining data-access level and
|
||||||
|
tariff for service usage.
|
||||||
|
|
||||||
|
• Data services maintenance access, for services providers reviewing, extending or editing
|
||||||
|
applications in the urban platform. Data services providers can view their services deployed
|
||||||
|
and add to or edit access level and tariff without having to deploy the services again. They
|
||||||
|
should be provided with access to feedback from users to investigate problem in their services
|
||||||
|
(e.g. bugs, scalability issues), and statistical information about how their services are used by
|
||||||
|
users.
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 10
|
||||||
|
|
||||||
|
|
||||||
|
1.8.4 Platform Provider Access
|
||||||
|
|
||||||
|
This is the most restrictive access level providing ultimate rights to the system and is required for
|
||||||
|
its management, development, and assigning appropriate rights to data and services providers.
|
||||||
|
Policies and regulations, license agreements are also defined by the provider of the urban
|
||||||
|
platform. Platform providers should be provided with the means to follow up on civic engagement
|
||||||
|
(e.g. feedback, request for city data) and on the provision of city data and services.
|
||||||
|
|
||||||
|
|
||||||
|
1.9 User Documentation
|
||||||
|
• City Data Consumers: Provide license terms and conditions associated to consuming
|
||||||
|
data and services provided in the platform, documentation of APIs and guide to
|
||||||
|
discover city data in the platform.
|
||||||
|
• City Data Providers: Provide data publication documentation describing the minimum
|
||||||
|
metadata requirements, formats accepted, step-by-step guide to publish accurate city
|
||||||
|
data.
|
||||||
|
• Data Service Providers: Disclosure technical and architecture blueprint details in
|
||||||
|
order share and outsource expertise, and partnerships, and integrate supporting
|
||||||
|
partners’ solutions into the platform itself.
|
||||||
|
|
||||||
|
|
||||||
|
1.10 Design and Implementation Constraints
|
||||||
|
1.10.1 Design Constraints
|
||||||
|
|
||||||
|
• Lack of standards agreement for metadata representation.
|
||||||
@@ -0,0 +1,600 @@
|
|||||||
|
• City data found in existing data catalogues may require special consideration concerning the
|
||||||
|
type of formats and datasets that must be stored within the platform.
|
||||||
|
• Requirements mismatch due to increased number of stakeholders involved in the design
|
||||||
|
|
||||||
|
|
||||||
|
1.10.2 Implementation Constraints
|
||||||
|
|
||||||
|
• Evaluation and testing of software options is expected to occur prior to selection and
|
||||||
|
implementation of a production urban platform.
|
||||||
|
• Budget costs are unknown until evaluation of software options is completed.
|
||||||
|
|
||||||
|
|
||||||
|
1.11 Assumptions, Alignment with other Action Clusters and Policies
|
||||||
|
1.11.1 Assumptions
|
||||||
|
|
||||||
|
The assumptions in Table 3 have been identified by the Demand Side Engagement Stream as
|
||||||
|
relevant to this Requirements Specification.
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 11
|
||||||
|
|
||||||
|
|
||||||
|
Table 3. Assumptions
|
||||||
|
|
||||||
|
# ASSUMPTION
|
||||||
|
|
||||||
|
1 The providers of city data and services will be responsible to maintain their resources in the platform.
|
||||||
|
|
||||||
|
2 All city data must meet the minimum metadata requirements and use the standards adopted by the platform.
|
||||||
|
|
||||||
|
3 The platform shall consider open Source as an optional commercial model, with open standards as a principle
|
||||||
|
|
||||||
|
4 The system design and architecture should minimize fragmentation of city data in the urban platform.
|
||||||
|
|
||||||
|
5 To the extent possible, automation should be used for the extraction of descriptive and technical metadata.
|
||||||
|
|
||||||
|
6 The platform must be designed in a way it accommodates additional functionality at later stage at a fair and transparent cost.
|
||||||
|
|
||||||
|
The platform must be a modular based architecture which relies on stable and well-defined open interfaces to ensure
|
||||||
|
7
|
||||||
|
interoperability between the platform, services and the applications provided by service providers.
|
||||||
|
|
||||||
|
The platform will offer open and well-documented API’s and clear service descriptions and contracts that is offered for reuse by
|
||||||
|
8 another party to foster open innovation in the city, which means that developers and interested individuals openly utilize the
|
||||||
|
resources provided.
|
||||||
|
|
||||||
|
9 Adopt open and published European and International standards where possible.
|
||||||
|
|
||||||
|
The platform must be flexible enough to accommodate different local, National and International data protection, licensing and
|
||||||
|
10
|
||||||
|
commercialization regulations.
|
||||||
|
|
||||||
|
11 Platform providers will monitor emerging technologies in order to maintain and improve the architecture.
|
||||||
|
|
||||||
|
|
||||||
|
12 Platform providers will monitor emerging information standards, including metadata standards and data interface standards.
|
||||||
|
|
||||||
|
|
||||||
|
13 Platform providers will monitor new commercial models for city data exploitation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
1.11.2 Alignment with Citizen’s Focus Action Cluster
|
||||||
|
This specification document is aligned with the principles defined in the Citizen Focus5 Action
|
||||||
|
Cluster of the European Innovation Partnership on Smart Cities and Communities. Citizen Focus’ is
|
||||||
|
about “working together with citizens to realize public interests at the intersection of ICT, mobility
|
||||||
|
and energy in an urban environment”. We recognize citizens as owners of and participants in
|
||||||
|
the creation and delivery of city data and digital services, and we specify requirements to deliver
|
||||||
|
new digital services that will address the societal needs of cities in a positive manner that relates to
|
||||||
|
political narratives. Societal needs and wants are considered the starting point for city data service
|
||||||
|
offering by the urban platform. The requirements in this document were elicited considering
|
||||||
|
|
||||||
|
• Human behaviour and needs as important as technology;
|
||||||
|
• The services and data that solve social problems and drive innovation;
|
||||||
|
• The mechanisms that make data and services more accessible to users;
|
||||||
|
• The factors that influences user’s experience while interacting with services provided (e.g.
|
||||||
|
usability, feeling of security and trust);
|
||||||
|
|
||||||
|
|
||||||
|
5
|
||||||
|
https://eu-smartcities.eu/node/1333
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 12
|
||||||
|
|
||||||
|
|
||||||
|
1.11.3 Policies to be developed
|
||||||
|
|
||||||
|
The following policies have been identified by the Demand Side Engagement Stream as relevant to
|
||||||
|
this Requirements Specification.
|
||||||
|
|
||||||
|
• Data formatting and Metadata Schemes: Urban platforms will require more expansive, robust
|
||||||
|
and useful data encoding and conversion that what is available in existing data catalogues.
|
||||||
|
Data preservation policies should be developed to allow data to be stored in formats that can
|
||||||
|
be migrated, associated with metadata and ontologies to become both humans and machines
|
||||||
|
readable and understandable, ongoing monitoring for data obsolescence, and migrating data to
|
||||||
|
systems environments as needed to ensure their continued availability. Current Metadata
|
||||||
|
schemes (e.g. open data, sensory data ontologies) should be reviewed to see if it meets
|
||||||
|
current needs for city data management. It is possible that the needs of the urban platform
|
||||||
|
designed here may require new or additional schemas.
|
||||||
|
|
||||||
|
• Data commercialisation: The commercial exploitation of city data and their funding models
|
||||||
|
are unexplored concepts that we are committed to address. There is an urgent need to define
|
||||||
|
license agreements and fair commercial and subscription models to allow interoperable open
|
||||||
|
and proprietary data to co-exist in the platform.
|
||||||
|
|
||||||
|
• Data publication and services deployment: Policy development will be needed regarding
|
||||||
|
ingesting data and deploying data services into the platform, including which users/machines
|
||||||
|
will be authorized to submit data for publication, the minimum requirements for data submitted
|
||||||
|
by open and proprietary data publishers, and the removal of resources and services from the
|
||||||
|
platform.
|
||||||
|
|
||||||
|
|
||||||
|
2. Urban Platform Value Proposition, Use Cases and
|
||||||
|
Functional Requirements
|
||||||
|
2.1 From Value Proposition to Platform Specifications
|
||||||
|
This document uses goal-oriented modelling for eliciting, elaborating, structuring, specifying,
|
||||||
|
documenting, and modifying requirements. Goals represent the objectives which the urban
|
||||||
|
platform should achieve through cooperation of actors in the intended system and in the
|
||||||
|
environment. They capture, at different levels of abstraction, the various objectives the urban
|
||||||
|
platform under design should achieve. Through goals modelling we consider how the value
|
||||||
|
proposition and intended solutions connects across the stack, how the urban platform meets city
|
||||||
|
goals, why the system and its functionality are needed, and how the stakeholders’ interests may be
|
||||||
|
addressed.
|
||||||
|
|
||||||
|
In our specification, we present the overall goal (the value proposition) that the urban platform
|
||||||
|
should aim to achieve in order to be considered as a viable final product, and a set of sub-goals
|
||||||
|
(intended solutions) it should maintain in the long run so that the overall goal can be unceasingly
|
||||||
|
achieved. By using this approach, the low-level technical requirements can be traced back to high-
|
||||||
|
level strategic objectives of the urban platform. The formal notations used in this document are:
|
||||||
|
Achieve [“Name of Overall Goal”] and Maintain [“Name of Sub-Goal”]. The requirements of the
|
||||||
|
Urban Platform are noted for each of the sub-goals, and are presented as a series of statements
|
||||||
|
regarding the capabilities needed in to achieve the overall goal of the Urban Platform.
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 13
|
||||||
|
|
||||||
|
|
||||||
|
2.2 Overall Goal: “City data is exploited to its full potential”
|
||||||
|
An urban platform is an organization of people and systems, which has accepted the responsibility
|
||||||
|
to preserve city data and make it available for all the stakeholders of smart cities. Ultimately, an
|
||||||
|
urban platform is a foundation for the full exploitation of city data. Hence, the major goal an Urban
|
||||||
|
Platform must achieve is “city data is exploited to its full potential”. To achieve this high level goal,
|
||||||
|
the urban platform must maintain in the long run the five sub-goals illustrated in Figure 3.
|
||||||
|
|
||||||
|
Each one of the defined sub-goals co-enables the achievement of the specified high-level (overall)
|
||||||
|
goal of the urban platform. The sub-goals include the ingestion of city data, metadata generation,
|
||||||
|
data management, data storage, access, preservation, and administration, provision of engaging
|
||||||
|
services in the smart cities. These sub-goals are discussed in details in the following sections.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Achieve [City data is exploited How we achieve the platform overall goal?
|
||||||
|
Why do we need the sub-goals?
|
||||||
|
to its full effect]
|
||||||
|
Goal
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Maintain [User s experience is
|
||||||
|
Maintain [City data is provided
|
||||||
|
enhanced by the provision of
|
||||||
|
in a harmonised way]
|
||||||
|
S ub-Goal 1 S ub-Goal 5 value-added services]
|
||||||
|
co-ena bles
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Maintain [Resources are managed in Maintain [City data is offered
|
||||||
|
a safe and intelligent manner] in an accessible manner]
|
||||||
|
S ub-Goal 2 S ub-Goal 4
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Maintain [City data is orchestrated
|
||||||
|
in a market place]
|
||||||
|
S ub-Goal 3
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Figure 3. Platform High-Level Goal and its respective sub-goals.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
2.2.1 Urban Platform Boundary
|
||||||
|
|
||||||
|
The use case diagram illustrated in Figure 4 identifies the boundaries between the actors (either
|
||||||
|
automated or human) and the urban platform. We have arrived at the urban platform boundary by
|
||||||
|
inspecting each business use case and determining, in conjunction with the stakeholders needs,
|
||||||
|
which part of the business use case should be implemented and what part should be done by an
|
||||||
|
outsourced product (e.g. Billing System) using the framework 4.
|
||||||
|
|
||||||
|
This task is technology agnostic and takes into account the abilities of the users/actors, the
|
||||||
|
constraints, the goals of the urban platform. Table 4 maps out the use cases with their respective
|
||||||
|
sub-goals and actors.
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 14
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Manage Services
|
||||||
|
|
||||||
|
S ub-Goal 5
|
||||||
|
|
||||||
|
|
||||||
|
Data Service
|
||||||
|
Publish City Data
|
||||||
|
Provider
|
||||||
|
S ub-Goal 1
|
||||||
|
|
||||||
|
|
||||||
|
<<include>> Deploy Data Services
|
||||||
|
rules
|
||||||
|
S ub-Goal 5
|
||||||
|
|
||||||
|
Authenticate in the
|
||||||
|
Manage Resources <<include>>
|
||||||
|
Platform Platform
|
||||||
|
S ub-Goal 1 Provider Database
|
||||||
|
<<include>> Manage Infrastructure System
|
||||||
|
S ub-Goal 2
|
||||||
|
|
||||||
|
Utlise Data Services
|
||||||
|
City Data <<include>>
|
||||||
|
Publisher S ub-Goal 5
|
||||||
|
|
||||||
|
Store City Data Management
|
||||||
|
<<include>>
|
||||||
|
S ub-Goal 2
|
||||||
|
Systems Services
|
||||||
|
System
|
||||||
|
|
||||||
|
<<include>>
|
||||||
|
City Data
|
||||||
|
Consumer
|
||||||
|
QoS Monitoring
|
||||||
|
Transmit Data
|
||||||
|
System
|
||||||
|
Register in the Platform S ub-Goal 2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<<include>>
|
||||||
|
rules
|
||||||
|
|
||||||
|
<<extend>>
|
||||||
|
rules
|
||||||
|
Platform
|
||||||
|
Provider
|
||||||
|
rules
|
||||||
|
|
||||||
|
Commercialise Data
|
||||||
|
Consume City Data
|
||||||
|
Services City Data
|
||||||
|
S ub-Goal 3 S ub-Goal 4
|
||||||
|
Consumer
|
||||||
|
<<extend>>
|
||||||
|
|
||||||
|
|
||||||
|
Commercialise
|
||||||
|
City Data Discover City Data
|
||||||
|
S ub-Goal 3
|
||||||
|
S ub-Goal 4
|
||||||
|
|
||||||
|
Billing
|
||||||
|
Management
|
||||||
|
System
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Authenticate in the Register in the
|
||||||
|
Platform Platform
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Authenticate Authenticate
|
||||||
|
Register Consumers Register Publishers
|
||||||
|
Consumers Publishers
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Figure 4. Simplistic overview of the use cases identified in the early stages of the platform design.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Table 4. Use Cases Mapping with Sub-Goals and Actors
|
||||||
|
Sub-Goals Use Cases ID Specialised Use Cases Actors
|
||||||
|
HIGH-LEVEL GOAL: City data is exploited to its
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Publish City Data UC1 User publishes city data via data API’s
|
||||||
|
City Data Publisher
|
||||||
|
1. City data is Register as a publisher
|
||||||
|
UC2 User manually uploads datasets
|
||||||
|
provided in a in the Platform
|
||||||
|
harmonised way
|
||||||
|
full effect
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
User manages resources
|
||||||
|
Manage Resources UC3 City Data Publisher
|
||||||
|
User tracks resources usage
|
||||||
|
|
||||||
|
Store City Data UC4
|
||||||
|
2. City data is
|
||||||
|
managed in a safe Transmit Data UC5 - Management Systems
|
||||||
|
and intelligent
|
||||||
|
manner
|
||||||
|
Manage Infrastructure UC6
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 15
|
||||||
|
|
||||||
|
|
||||||
|
City Data Publisher
|
||||||
|
Set commercial city data
|
||||||
|
Platform Provider
|
||||||
|
Subscribe to proprietary data City Data Consumer
|
||||||
|
Commercialise City
|
||||||
|
UC7
|
||||||
|
Data
|
||||||
|
Manage commercial data City Data Publisher
|
||||||
|
|
||||||
|
3. City data is Manage data subscription City Data Consumer
|
||||||
|
orchestrated in a
|
||||||
|
Data Services Provider
|
||||||
|
market place Set commercial data services
|
||||||
|
Platform Provider
|
||||||
|
Subscribe to commercial services Data Services Consumer
|
||||||
|
Commercialise Data
|
||||||
|
UC8
|
||||||
|
Services
|
||||||
|
Manage commercial services Data Services Provider
|
||||||
|
|
||||||
|
Manage services subscription Data Services Consumer
|
||||||
|
UC9
|
||||||
|
Register in the Platform City Data Consumer
|
||||||
|
-
|
||||||
|
4. City data is Discover City Data City Data Consumer
|
||||||
|
UC10
|
||||||
|
offered in an
|
||||||
|
User consumes city data via data
|
||||||
|
accessible manner
|
||||||
|
API’s
|
||||||
|
Consume City Data UC11 City Data Consumer
|
||||||
|
User downloads datasets
|
||||||
|
5. User’s Data Services Provider
|
||||||
|
Deploy Data Services UC12
|
||||||
|
experience is Platform Provider
|
||||||
|
enhanced by the
|
||||||
|
Manage Services UC13 - Data Services Provider
|
||||||
|
provision of value-
|
||||||
|
added services
|
||||||
|
Utilise Data Services UC14 City Data Consumer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
2.3 SUB-GOAL 1: City data is collected in an intelligent manner
|
||||||
|
Description: The urban platform enables the owners of city data to easily publish both historic and
|
||||||
|
data streams in the platform, as well as their associated metadata.
|
||||||
|
Rationale: This sub-goal is maintained by the services and functions to accept the publication of
|
||||||
|
city data from data providers (of both open and proprietary data) and prepare the contents for
|
||||||
|
storage and management within the urban platform. Functions include receiving data, performing
|
||||||
|
quality assurance on data, verifying data formatting and document standards, associating meta-
|
||||||
|
data information, and coordinating updates to databases and resources management.
|
||||||
|
|
||||||
|
Achieve [City data is exploited
|
||||||
|
to its full effect]
|
||||||
|
Goal
|
||||||
|
co-ena bles
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
How we achieve the platform overall goal?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Maintain [City data is provided in
|
||||||
|
a harmonised manner]
|
||||||
|
S ub-Goal 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
What actions can maintain the sub-goal?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Achieve [Register Publisher] Achieve [Publish City Data] Achieve [Manage Resources]
|
||||||
|
UC1 UC2 UC3
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Figure 5. Sub-Goal 1 “City data is collected in an intelligent manner” refinement.
|
||||||
|
|
||||||
|
|
||||||
|
Drivers: Ensure data is published in an easy and uniform way.
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 16
|
||||||
|
|
||||||
|
|
||||||
|
Actions: For Sub-Goal 1 to be maintained in the long-run it requires the efficient realisation of use
|
||||||
|
cases: “Publish City Data” and “Manage Resources”, as shown in Figure 5.
|
||||||
|
|
||||||
|
|
||||||
|
2.3.1 Use Case: Register Publisher
|
||||||
|
ID: UC1
|
||||||
|
Refines: SUB-GOAL 1: City data is collected in an intelligent manner
|
||||||
|
Pre-condition: Data Publisher is not logged in the system
|
||||||
|
Actors: Data Publishers
|
||||||
|
Rationale: Data Publishers can register in the platform and request approval to submit city data.
|
||||||
|
They provide valid registration details (to be defined) and wait for registration confirmation.
|
||||||
|
Platform Providers may authorise or not data publishers to offer both open and proprietary city data
|
||||||
|
in the platform. Data submission agreement is a formal agreement between the Data Provider and
|
||||||
|
the Urban Platform defining the terms of the content, standards, metadata creation, and license
|
||||||
|
agreement. The Urban Platform will proactively work with Data Providers to agree on the content,
|
||||||
|
quality and format of city data. Agreements between Platform and Data Providers may be
|
||||||
|
renegotiated on a periodic or ad-hoc basis.
|
||||||
|
Refines into requirements: FREQ.1 to FREQ.5.
|
||||||
|
|
||||||
|
Use Case Basic Stimulus and Responses
|
||||||
|
1. The platform prompts the user for a username and password or
|
||||||
|
register new account.
|
||||||
|
2. The user selects registration option.
|
||||||
|
3. The platform prompts user for publisher registration information (e.g.
|
||||||
|
username, password, organisation)
|
||||||
|
4. The user enters in their information.
|
||||||
|
UC1. Register 5. Platform verifies information and creates account.
|
||||||
|
Publisher o If non-valid information, platform shows error message and
|
||||||
|
returns to step 1.
|
||||||
|
6. Platform provider is requested to approve the account
|
||||||
|
o Platform acknowledges registration has been successful
|
||||||
|
o If non approved, platform shows error message and returns to
|
||||||
|
step 1.
|
||||||
|
7. End of registration
|
||||||
|
|
||||||
|
|
||||||
|
2.3.2 Use Case: Publish City Data
|
||||||
|
ID: UC2
|
||||||
|
Refines: SUB-GOAL 1 - City data is collected in an intelligent manner
|
||||||
|
Pre-condition: User is authenticated in the platform
|
||||||
|
Actors: City data publisher
|
||||||
|
Rationale: The Publish City Data function provides the appropriate mechanisms to receive city data from
|
||||||
|
authorized data providers. Data may be manually uploaded or submitted via APIs. In general, data providers
|
||||||
|
with whom the Urban Platform negotiates submission agreements are the providers of proprietary city data
|
||||||
|
(those producing published material, i.e. publishers) and open data, and they can be either humans or
|
||||||
|
machines. The providers of the Urban Platform will provide data providers with specifications on the content,
|
||||||
|
quality and format of data, and publication terms and conditions.
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 17
|
||||||
|
|
||||||
|
|
||||||
|
The Publish City Data function may represent a legal transfer of custody for the data in the urban platform,
|
||||||
|
and may require that special access controls be placed on the contents. This function provides a
|
||||||
|
confirmation of receipt of data publication to the Producer, which may include a request to resubmit data in
|
||||||
|
the case of errors resulting from the submission.
|
||||||
|
Once data has arrived, it must undergo several reviews, including virus checking, format compliance,
|
||||||
|
metadata minimum requirement agreement, quality and anticipated content and data formatting. The
|
||||||
|
platform must include the ability to record all actions and decisions made concerning the publication of city
|
||||||
|
data. The reasons for publication failure (e.g. missing metadata information, non-valid dataset) will be
|
||||||
|
provided back to the city data publisher. In some cases, the provider can then resubmit corrected data and
|
||||||
|
metadata information, while in other instances data publication refusal criteria should prevent the publisher
|
||||||
|
from submitting the same dataset at a later time period (e.g. in cases of suspicious datasets – copyrights
|
||||||
|
violation, viruses). When data is successfully submitted (either via APIs or manual upload), it will be
|
||||||
|
processed/prepared for storage into the platform’s database.
|
||||||
|
Specialised Use Cases: The Use Case Publish City Data data is distinguished into two
|
||||||
|
specialised Use Cases: “User publishes city data via data API’s (UC2.1)” and “User manually
|
||||||
|
uploads datasets (UC2.2)”.
|
||||||
|
Subordinated Use Cases: “Store City Data (UC4)”
|
||||||
|
Refines into requirements: FREQ 6 to FREQ.26.
|
||||||
|
|
||||||
|
|
||||||
|
Specialised Use Cases Basic Stimulus and Responses
|
||||||
|
1. Platform provides user with an interface for static data
|
||||||
|
publication
|
||||||
|
2. User selects datasets to be uploaded
|
||||||
|
3. User provides metadata associated with the data (license,
|
||||||
|
provenance, ownership, semantics) in accordance with defined
|
||||||
|
standards
|
||||||
|
UC2.1. User manually 4. User requests data publication
|
||||||
|
uploads datasets 5. Platform quickly process user’s request for data publication
|
||||||
|
6. Platform validates data submitted
|
||||||
|
o If valid data, platform acknowledges data publication has
|
||||||
|
been successful
|
||||||
|
o If non-valid data, platform shows error message and returns
|
||||||
|
to step 1.
|
||||||
|
7. End of data publication
|
||||||
|
1. Platform provides user with an interface for real-time data
|
||||||
|
publication
|
||||||
|
2. User input data API information
|
||||||
|
3. User provides metadata associated with the data (license,
|
||||||
|
provenance, ownership, semantics) in accordance with defined
|
||||||
|
standards
|
||||||
|
UC2.2. User publishes 4. User confirm information and request data publication
|
||||||
|
city data via data API’s 5. Platform quickly process user’s request for data publication
|
||||||
|
6. Platform validates data submitted
|
||||||
|
o If valid data, platform acknowledges data publication has
|
||||||
|
been successful
|
||||||
|
o If non-valid data, platform shows error message and returns
|
||||||
|
to step 1
|
||||||
|
End of data publication
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 18
|
||||||
|
|
||||||
|
|
||||||
|
2.3.3 Use Case: Manage Resources
|
||||||
|
ID: UC3
|
||||||
|
Refines: GOAL 1: City data is collected in an intelligent manner
|
||||||
|
Pre-condition: User successfully authenticates in the platform
|
||||||
|
Actors: City data publisher
|
||||||
|
Rationale: Manage resources provides the services and functions for updating, maintaining and
|
||||||
|
accessing both data and metadata, as well as tracking the usage of resources by users. Ideally
|
||||||
|
the owners of the resources should be the only authorised user to manage resources, and other
|
||||||
|
authorised users can track the usage of the resources in the platform. The platform must provide a
|
||||||
|
database update response indicating the status of the update, avoid update errors to be
|
||||||
|
propagated in the platform, and should keep an audit trail of all actions to enable rollback. Data
|
||||||
|
usage tracking includes performing queries on the data management data to generate result sets,
|
||||||
|
and producing reports from these result sets.
|
||||||
|
Specialised Use Cases: The Use Case Manage Resources data is distinguished into two
|
||||||
|
specialised Use Cases: “User manages resources (UC3.1)” and “User tracks resources usage
|
||||||
|
(UC3.2)”.
|
||||||
|
Subordinated Use Cases: “Transmit Data (UC5)”
|
||||||
|
Refines into requirements: FREQ.27 to FREQ.25.
|
||||||
|
|
||||||
|
|
||||||
|
Specialised Use Cases Basic Interactions and Responses
|
||||||
|
1. Platform provides user with an interface for resources
|
||||||
|
management (e.g. data and metadata, data usage)
|
||||||
|
2. User chooses to edit or delete data
|
||||||
|
3. If edit, user revise metadata associated with the data (license,
|
||||||
|
provenance, ownership, access-control, semantics);
|
||||||
|
UC3.1. User manages 4. If delete, user selects dataset(s) to be removed
|
||||||
|
resources 5. User confirms action
|
||||||
|
6. Platform quickly process user’s request
|
||||||
|
7. Platform confirms execution of request
|
||||||
|
o If valid request, platform acknowledges request has been
|
||||||
|
processed successfully
|
||||||
|
o If non-valid request, platform returns to step 1.
|
||||||
|
8. End of resources management
|
||||||
|
1. Platform provides user with an interface for resources
|
||||||
|
management (e.g. data and metadata, data usage)
|
||||||
|
2. User chooses to visualise usage information of a dataset
|
||||||
|
UC3.2. User tracks 3. Platform quickly process user’s request for data usage
|
||||||
|
resources usage information
|
||||||
|
4. Platform provides user with statistical information about data
|
||||||
|
usage and data users anonymised information
|
||||||
|
5. End of data usage tracking.
|
||||||
|
|
||||||
|
|
||||||
|
2.3.4 Functional Requirements
|
||||||
|
|
||||||
|
Req. ID UC. ID Description Priority Domain
|
||||||
|
Societal Needs,
|
||||||
|
FREQ.1 UC1 Allow data publishers to register to submit data for publication Must
|
||||||
|
Platform
|
||||||
|
Tracks data publication agreements between Data and Platform Business Needs,
|
||||||
|
FREQ.2 UC1 Must
|
||||||
|
Providers Platform
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 19
|
||||||
|
|
||||||
|
|
||||||
|
Store terms of agreements, and use them to monitor/review/process
|
||||||
|
FREQ.3 UC1 Must City Data, Platform
|
||||||
|
data submissions.
|
||||||
|
Able to add and edit terms of agreement, based on access of level of Business Needs,
|
||||||
|
FREQ.4 UC1 Must
|
||||||
|
user. Platform
|
||||||
|
|
||||||
|
FREQ.5 UC1 Data publications are managed and monitored Must City Data, Platform
|
||||||
|
|
||||||
|
Allow authenticated users from across different organisations to City Data, Platform,
|
||||||
|
FREQ.6 UC2 Must
|
||||||
|
publish city data Business Needs
|
||||||
|
Provide authorization mechanisms for users and sensors to publish
|
||||||
|
FREQ.7 UC2 Must City Data, Platform
|
||||||
|
city data
|
||||||
|
City Data, Platform,
|
||||||
|
FREQ.9 UC2 Provide mechanisms for static data publication Must
|
||||||
|
Business Needs
|
||||||
|
City Data, Platform,
|
||||||
|
FREQ.10 UC2 Provide mechanisms for real-time data publication Must
|
||||||
|
Business Needs
|
||||||
|
|
||||||
|
FREQ.11 UC2 Enable the publication of metadata Must City Data, Platform
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.12 UC2 Maintain temporal information about the data Must City Data, Platform
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.13 UC2 Support sensory data collection Must City Data, Platform
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.14 UC2 Accepts content in numerous file types/formats Must City Data, Platform
|
||||||
|
|
||||||
|
Prompts a request for resubmission to the data provider if an error of
|
||||||
@@ -0,0 +1,600 @@
|
|||||||
|
harmonised way
|
||||||
|
full effect
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
User manages resources
|
||||||
|
Manage Resources UC3 City Data Publisher
|
||||||
|
User tracks resources usage
|
||||||
|
|
||||||
|
Store City Data UC4
|
||||||
|
2. City data is
|
||||||
|
managed in a safe Transmit Data UC5 - Management Systems
|
||||||
|
and intelligent
|
||||||
|
manner
|
||||||
|
Manage Infrastructure UC6
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 15
|
||||||
|
|
||||||
|
|
||||||
|
City Data Publisher
|
||||||
|
Set commercial city data
|
||||||
|
Platform Provider
|
||||||
|
Subscribe to proprietary data City Data Consumer
|
||||||
|
Commercialise City
|
||||||
|
UC7
|
||||||
|
Data
|
||||||
|
Manage commercial data City Data Publisher
|
||||||
|
|
||||||
|
3. City data is Manage data subscription City Data Consumer
|
||||||
|
orchestrated in a
|
||||||
|
Data Services Provider
|
||||||
|
market place Set commercial data services
|
||||||
|
Platform Provider
|
||||||
|
Subscribe to commercial services Data Services Consumer
|
||||||
|
Commercialise Data
|
||||||
|
UC8
|
||||||
|
Services
|
||||||
|
Manage commercial services Data Services Provider
|
||||||
|
|
||||||
|
Manage services subscription Data Services Consumer
|
||||||
|
UC9
|
||||||
|
Register in the Platform City Data Consumer
|
||||||
|
-
|
||||||
|
4. City data is Discover City Data City Data Consumer
|
||||||
|
UC10
|
||||||
|
offered in an
|
||||||
|
User consumes city data via data
|
||||||
|
accessible manner
|
||||||
|
API’s
|
||||||
|
Consume City Data UC11 City Data Consumer
|
||||||
|
User downloads datasets
|
||||||
|
5. User’s Data Services Provider
|
||||||
|
Deploy Data Services UC12
|
||||||
|
experience is Platform Provider
|
||||||
|
enhanced by the
|
||||||
|
Manage Services UC13 - Data Services Provider
|
||||||
|
provision of value-
|
||||||
|
added services
|
||||||
|
Utilise Data Services UC14 City Data Consumer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
2.3 SUB-GOAL 1: City data is collected in an intelligent manner
|
||||||
|
Description: The urban platform enables the owners of city data to easily publish both historic and
|
||||||
|
data streams in the platform, as well as their associated metadata.
|
||||||
|
Rationale: This sub-goal is maintained by the services and functions to accept the publication of
|
||||||
|
city data from data providers (of both open and proprietary data) and prepare the contents for
|
||||||
|
storage and management within the urban platform. Functions include receiving data, performing
|
||||||
|
quality assurance on data, verifying data formatting and document standards, associating meta-
|
||||||
|
data information, and coordinating updates to databases and resources management.
|
||||||
|
|
||||||
|
Achieve [City data is exploited
|
||||||
|
to its full effect]
|
||||||
|
Goal
|
||||||
|
co-ena bles
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
How we achieve the platform overall goal?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Maintain [City data is provided in
|
||||||
|
a harmonised manner]
|
||||||
|
S ub-Goal 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
What actions can maintain the sub-goal?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Achieve [Register Publisher] Achieve [Publish City Data] Achieve [Manage Resources]
|
||||||
|
UC1 UC2 UC3
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Figure 5. Sub-Goal 1 “City data is collected in an intelligent manner” refinement.
|
||||||
|
|
||||||
|
|
||||||
|
Drivers: Ensure data is published in an easy and uniform way.
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 16
|
||||||
|
|
||||||
|
|
||||||
|
Actions: For Sub-Goal 1 to be maintained in the long-run it requires the efficient realisation of use
|
||||||
|
cases: “Publish City Data” and “Manage Resources”, as shown in Figure 5.
|
||||||
|
|
||||||
|
|
||||||
|
2.3.1 Use Case: Register Publisher
|
||||||
|
ID: UC1
|
||||||
|
Refines: SUB-GOAL 1: City data is collected in an intelligent manner
|
||||||
|
Pre-condition: Data Publisher is not logged in the system
|
||||||
|
Actors: Data Publishers
|
||||||
|
Rationale: Data Publishers can register in the platform and request approval to submit city data.
|
||||||
|
They provide valid registration details (to be defined) and wait for registration confirmation.
|
||||||
|
Platform Providers may authorise or not data publishers to offer both open and proprietary city data
|
||||||
|
in the platform. Data submission agreement is a formal agreement between the Data Provider and
|
||||||
|
the Urban Platform defining the terms of the content, standards, metadata creation, and license
|
||||||
|
agreement. The Urban Platform will proactively work with Data Providers to agree on the content,
|
||||||
|
quality and format of city data. Agreements between Platform and Data Providers may be
|
||||||
|
renegotiated on a periodic or ad-hoc basis.
|
||||||
|
Refines into requirements: FREQ.1 to FREQ.5.
|
||||||
|
|
||||||
|
Use Case Basic Stimulus and Responses
|
||||||
|
1. The platform prompts the user for a username and password or
|
||||||
|
register new account.
|
||||||
|
2. The user selects registration option.
|
||||||
|
3. The platform prompts user for publisher registration information (e.g.
|
||||||
|
username, password, organisation)
|
||||||
|
4. The user enters in their information.
|
||||||
|
UC1. Register 5. Platform verifies information and creates account.
|
||||||
|
Publisher o If non-valid information, platform shows error message and
|
||||||
|
returns to step 1.
|
||||||
|
6. Platform provider is requested to approve the account
|
||||||
|
o Platform acknowledges registration has been successful
|
||||||
|
o If non approved, platform shows error message and returns to
|
||||||
|
step 1.
|
||||||
|
7. End of registration
|
||||||
|
|
||||||
|
|
||||||
|
2.3.2 Use Case: Publish City Data
|
||||||
|
ID: UC2
|
||||||
|
Refines: SUB-GOAL 1 - City data is collected in an intelligent manner
|
||||||
|
Pre-condition: User is authenticated in the platform
|
||||||
|
Actors: City data publisher
|
||||||
|
Rationale: The Publish City Data function provides the appropriate mechanisms to receive city data from
|
||||||
|
authorized data providers. Data may be manually uploaded or submitted via APIs. In general, data providers
|
||||||
|
with whom the Urban Platform negotiates submission agreements are the providers of proprietary city data
|
||||||
|
(those producing published material, i.e. publishers) and open data, and they can be either humans or
|
||||||
|
machines. The providers of the Urban Platform will provide data providers with specifications on the content,
|
||||||
|
quality and format of data, and publication terms and conditions.
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 17
|
||||||
|
|
||||||
|
|
||||||
|
The Publish City Data function may represent a legal transfer of custody for the data in the urban platform,
|
||||||
|
and may require that special access controls be placed on the contents. This function provides a
|
||||||
|
confirmation of receipt of data publication to the Producer, which may include a request to resubmit data in
|
||||||
|
the case of errors resulting from the submission.
|
||||||
|
Once data has arrived, it must undergo several reviews, including virus checking, format compliance,
|
||||||
|
metadata minimum requirement agreement, quality and anticipated content and data formatting. The
|
||||||
|
platform must include the ability to record all actions and decisions made concerning the publication of city
|
||||||
|
data. The reasons for publication failure (e.g. missing metadata information, non-valid dataset) will be
|
||||||
|
provided back to the city data publisher. In some cases, the provider can then resubmit corrected data and
|
||||||
|
metadata information, while in other instances data publication refusal criteria should prevent the publisher
|
||||||
|
from submitting the same dataset at a later time period (e.g. in cases of suspicious datasets – copyrights
|
||||||
|
violation, viruses). When data is successfully submitted (either via APIs or manual upload), it will be
|
||||||
|
processed/prepared for storage into the platform’s database.
|
||||||
|
Specialised Use Cases: The Use Case Publish City Data data is distinguished into two
|
||||||
|
specialised Use Cases: “User publishes city data via data API’s (UC2.1)” and “User manually
|
||||||
|
uploads datasets (UC2.2)”.
|
||||||
|
Subordinated Use Cases: “Store City Data (UC4)”
|
||||||
|
Refines into requirements: FREQ 6 to FREQ.26.
|
||||||
|
|
||||||
|
|
||||||
|
Specialised Use Cases Basic Stimulus and Responses
|
||||||
|
1. Platform provides user with an interface for static data
|
||||||
|
publication
|
||||||
|
2. User selects datasets to be uploaded
|
||||||
|
3. User provides metadata associated with the data (license,
|
||||||
|
provenance, ownership, semantics) in accordance with defined
|
||||||
|
standards
|
||||||
|
UC2.1. User manually 4. User requests data publication
|
||||||
|
uploads datasets 5. Platform quickly process user’s request for data publication
|
||||||
|
6. Platform validates data submitted
|
||||||
|
o If valid data, platform acknowledges data publication has
|
||||||
|
been successful
|
||||||
|
o If non-valid data, platform shows error message and returns
|
||||||
|
to step 1.
|
||||||
|
7. End of data publication
|
||||||
|
1. Platform provides user with an interface for real-time data
|
||||||
|
publication
|
||||||
|
2. User input data API information
|
||||||
|
3. User provides metadata associated with the data (license,
|
||||||
|
provenance, ownership, semantics) in accordance with defined
|
||||||
|
standards
|
||||||
|
UC2.2. User publishes 4. User confirm information and request data publication
|
||||||
|
city data via data API’s 5. Platform quickly process user’s request for data publication
|
||||||
|
6. Platform validates data submitted
|
||||||
|
o If valid data, platform acknowledges data publication has
|
||||||
|
been successful
|
||||||
|
o If non-valid data, platform shows error message and returns
|
||||||
|
to step 1
|
||||||
|
End of data publication
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 18
|
||||||
|
|
||||||
|
|
||||||
|
2.3.3 Use Case: Manage Resources
|
||||||
|
ID: UC3
|
||||||
|
Refines: GOAL 1: City data is collected in an intelligent manner
|
||||||
|
Pre-condition: User successfully authenticates in the platform
|
||||||
|
Actors: City data publisher
|
||||||
|
Rationale: Manage resources provides the services and functions for updating, maintaining and
|
||||||
|
accessing both data and metadata, as well as tracking the usage of resources by users. Ideally
|
||||||
|
the owners of the resources should be the only authorised user to manage resources, and other
|
||||||
|
authorised users can track the usage of the resources in the platform. The platform must provide a
|
||||||
|
database update response indicating the status of the update, avoid update errors to be
|
||||||
|
propagated in the platform, and should keep an audit trail of all actions to enable rollback. Data
|
||||||
|
usage tracking includes performing queries on the data management data to generate result sets,
|
||||||
|
and producing reports from these result sets.
|
||||||
|
Specialised Use Cases: The Use Case Manage Resources data is distinguished into two
|
||||||
|
specialised Use Cases: “User manages resources (UC3.1)” and “User tracks resources usage
|
||||||
|
(UC3.2)”.
|
||||||
|
Subordinated Use Cases: “Transmit Data (UC5)”
|
||||||
|
Refines into requirements: FREQ.27 to FREQ.25.
|
||||||
|
|
||||||
|
|
||||||
|
Specialised Use Cases Basic Interactions and Responses
|
||||||
|
1. Platform provides user with an interface for resources
|
||||||
|
management (e.g. data and metadata, data usage)
|
||||||
|
2. User chooses to edit or delete data
|
||||||
|
3. If edit, user revise metadata associated with the data (license,
|
||||||
|
provenance, ownership, access-control, semantics);
|
||||||
|
UC3.1. User manages 4. If delete, user selects dataset(s) to be removed
|
||||||
|
resources 5. User confirms action
|
||||||
|
6. Platform quickly process user’s request
|
||||||
|
7. Platform confirms execution of request
|
||||||
|
o If valid request, platform acknowledges request has been
|
||||||
|
processed successfully
|
||||||
|
o If non-valid request, platform returns to step 1.
|
||||||
|
8. End of resources management
|
||||||
|
1. Platform provides user with an interface for resources
|
||||||
|
management (e.g. data and metadata, data usage)
|
||||||
|
2. User chooses to visualise usage information of a dataset
|
||||||
|
UC3.2. User tracks 3. Platform quickly process user’s request for data usage
|
||||||
|
resources usage information
|
||||||
|
4. Platform provides user with statistical information about data
|
||||||
|
usage and data users anonymised information
|
||||||
|
5. End of data usage tracking.
|
||||||
|
|
||||||
|
|
||||||
|
2.3.4 Functional Requirements
|
||||||
|
|
||||||
|
Req. ID UC. ID Description Priority Domain
|
||||||
|
Societal Needs,
|
||||||
|
FREQ.1 UC1 Allow data publishers to register to submit data for publication Must
|
||||||
|
Platform
|
||||||
|
Tracks data publication agreements between Data and Platform Business Needs,
|
||||||
|
FREQ.2 UC1 Must
|
||||||
|
Providers Platform
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 19
|
||||||
|
|
||||||
|
|
||||||
|
Store terms of agreements, and use them to monitor/review/process
|
||||||
|
FREQ.3 UC1 Must City Data, Platform
|
||||||
|
data submissions.
|
||||||
|
Able to add and edit terms of agreement, based on access of level of Business Needs,
|
||||||
|
FREQ.4 UC1 Must
|
||||||
|
user. Platform
|
||||||
|
|
||||||
|
FREQ.5 UC1 Data publications are managed and monitored Must City Data, Platform
|
||||||
|
|
||||||
|
Allow authenticated users from across different organisations to City Data, Platform,
|
||||||
|
FREQ.6 UC2 Must
|
||||||
|
publish city data Business Needs
|
||||||
|
Provide authorization mechanisms for users and sensors to publish
|
||||||
|
FREQ.7 UC2 Must City Data, Platform
|
||||||
|
city data
|
||||||
|
City Data, Platform,
|
||||||
|
FREQ.9 UC2 Provide mechanisms for static data publication Must
|
||||||
|
Business Needs
|
||||||
|
City Data, Platform,
|
||||||
|
FREQ.10 UC2 Provide mechanisms for real-time data publication Must
|
||||||
|
Business Needs
|
||||||
|
|
||||||
|
FREQ.11 UC2 Enable the publication of metadata Must City Data, Platform
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.12 UC2 Maintain temporal information about the data Must City Data, Platform
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.13 UC2 Support sensory data collection Must City Data, Platform
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.14 UC2 Accepts content in numerous file types/formats Must City Data, Platform
|
||||||
|
|
||||||
|
Prompts a request for resubmission to the data provider if an error of
|
||||||
|
FREQ.15 UC2 Must City Data, Platform
|
||||||
|
data transmission or receipt occurs
|
||||||
|
|
||||||
|
FREQ.16 UC2 Enable the semantic description of connected devices Must City Data, Platform
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.17 UC2 Gather data from authenticated and authorized devices Must City Data, Platform
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.18 UC2 Validates automatically the successful transfer of the data Must City Data, Platform
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.19 UC2 Performs virus checking on data Must City Data, Platform
|
||||||
|
|
||||||
|
Verifies the validity of the submission based on submitter, expected
|
||||||
|
FREQ.20 UC2 Must City Data, Platform
|
||||||
|
format, data quality, and completeness
|
||||||
|
Platform should have built-in checks on the incoming metadata. Data
|
||||||
|
FREQ.21 UC2 not containing the minimally defined set of attributes should be Must City Data, Platform
|
||||||
|
returned to the publisher for metadata enhancement.
|
||||||
|
System should have a user-friendly method of mapping non-standard
|
||||||
|
FREQ.22 UC2 Should City Data, Platform
|
||||||
|
metadata elements into approved standard elements.
|
||||||
|
Once ingested, metadata should be stored in a single common format.
|
||||||
|
FREQ.23 UC2 This format should be one that ensures against data loss, and allows a Must City Data, Platform
|
||||||
|
variety of access/distribution options
|
||||||
|
Data in the repository shall have sufficient technical metadata to
|
||||||
|
FREQ.24 UC2 assure functionality (e.g. viewing and display) to ensure accessibility Must City Data, Platform
|
||||||
|
and reusability.
|
||||||
|
Allows publishers to display and perform manual/visual quality control Business Needs, City
|
||||||
|
FREQ.25 UC2 Could
|
||||||
|
assurance via a user-friendly GUI Data, Platform
|
||||||
|
Business Needs, City
|
||||||
|
FREQ.26 UC2 Any errors shall prompt a request for resubmission of data Should
|
||||||
|
Data, Platform
|
||||||
|
|
||||||
|
FREQ.27 UC3 Enable data providers to manage their resources Must Business Needs
|
||||||
|
|
||||||
|
A minimal set of identifying information/metadata concerning data Business Needs,
|
||||||
|
FREQ.28 UC3 Must
|
||||||
|
publication submission must be recorded Platform
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 20
|
||||||
|
|
||||||
|
|
||||||
|
Stores and tracks versions of data. Links /connections between
|
||||||
|
FREQ.29 UC3 Must City Data, Platform
|
||||||
|
versions are created and maintained
|
||||||
|
Give service and data providers access to anonymized data of the Business Needs
|
||||||
|
FREQ.30 UC3 Should
|
||||||
|
subscribers of their data or services
|
||||||
|
City Data, Platform,
|
||||||
|
FREQ.31 UC3 Enable data providers to maintain and repair data and metadata Should
|
||||||
|
Business Needs
|
||||||
|
Tracks data publication agreements between Data and Platform Business Needs,
|
||||||
|
FREQ.32 UC3 Must
|
||||||
|
Providers Platform
|
||||||
|
Store terms of agreements, and use them to monitor/review/process
|
||||||
|
FREQ.33 UC3 Must City Data, Platform
|
||||||
|
data submissions.
|
||||||
|
Able to add and edit terms of agreement, based on access of level of Business Needs,
|
||||||
|
FREQ.34 UC3 Must
|
||||||
|
user. Platform
|
||||||
|
|
||||||
|
FREQ.35 UC3 Submission volumes and schedules are managed and monitored Must City Data, Platform
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
2.4 SUB-GOAL 2: City data is managed in a safe and intelligent manner
|
||||||
|
Rationale: The urban platform enables users to publish, consume and commercialise data, as well
|
||||||
|
as deploy and manage services all in a secure and privacy protected manner.
|
||||||
|
|
||||||
|
Achieve [City data is exploited
|
||||||
|
to its full effect]
|
||||||
|
Goal
|
||||||
|
co-ena bles
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Maintain [Resources are managed in a
|
||||||
|
safe and intelligent manner]
|
||||||
|
S ub-Goal 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Achieve [Store Data] Achieve [Transmit Data] Achieve [Manage Infrastructure]
|
||||||
|
UC4 UC5 UC6
|
||||||
|
|
||||||
|
|
||||||
|
Figure 6. Sub-Goal 2 “City data is managed in a safe and intelligent manner” refinement.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Drivers: Ensure data is secured and the identity of users are preserved
|
||||||
|
Actions: For Sub-Goal 2 to be maintained in the long-run it requires the efficient realisation of use
|
||||||
|
cases: “Store City Data” and “Retrieve and Transmit City Data”, as shown in Figure 6.
|
||||||
|
|
||||||
|
|
||||||
|
2.4.1 Use Case: Store City Data
|
||||||
|
ID: UC4
|
||||||
|
Refines: SUB-GOAL 2: City data is managed in a safe and intelligent manner
|
||||||
|
Pre-condition: Data is successfully published in the platform
|
||||||
|
Actors: Urban Platform
|
||||||
|
Rationale: When data is successfully submitted (either via APIs or manual upload), it is
|
||||||
|
processed/prepared for storage into the platform’s database. This procedure will include the
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 21
|
||||||
|
|
||||||
|
|
||||||
|
generation of unique identifiers to the database, enrichment with ontologies (when applicable),
|
||||||
|
encrypted (when applicable), signed with digital certificates (when applicable) to ensure that the
|
||||||
|
data conforms to the platform data formatting, standards, security and regulation. Data may be
|
||||||
|
converted to accepted formats, as needed (e.g. graph model). A primary goal of the conversion of
|
||||||
|
content for the platform is the preservation of the content. Priority will be given to preserving the
|
||||||
|
data accordingly to the policies defined in section (2.6.2). Access-control levels and license models
|
||||||
|
are associated to data which is subject to restrictions relating to access and conditions of use.
|
||||||
|
Refines into requirements: FREQ 28 – FREQ 39.
|
||||||
|
|
||||||
|
Use Case Basic Interactions and Responses
|
||||||
|
1. Platform mechanisms converts submitted data into a standard format
|
||||||
|
2. Security enforcement (e.g. anonymisation, cryptography) is placed on
|
||||||
|
sensitive information.
|
||||||
|
UC4. Store City 3. Platform associates with datasets the access-control definitions set by
|
||||||
|
Data owner of resources.
|
||||||
|
4. Data is enriched with semantics and is associated with other datasets
|
||||||
|
5. Platform stores data in a scalable and secure database.
|
||||||
|
6. End of data storage.
|
||||||
|
|
||||||
|
|
||||||
|
2.4.2 Use Case: Transmit Data
|
||||||
|
ID: UC5
|
||||||
|
Refines: SUB-GOAL 2: City data is managed in a safe and intelligent manner
|
||||||
|
Pre-condition: Data is successfully published in the platform
|
||||||
|
Actors: Urban Platform
|
||||||
|
Rationale: The platform accepts data retrieval request, validates user’s rights to access the data,
|
||||||
|
retrieves city data from data storage, and moves a copy of the data to the relevant platform
|
||||||
|
component for further processing. If special processing is required, the retrieval function accesses
|
||||||
|
data in staging storage and applies the requested processes. The types of operations, which may
|
||||||
|
be carried out, include sub-sampling in temporal or spatial dimensions, conversions between
|
||||||
|
different data types or output formats, and other specialized processing (e.g., data visualisation).
|
||||||
|
Once it is finalised data will be sent to the appropriate delivery channels (e.g. API’s, GUI). It also
|
||||||
|
encompasses function to verify corruption during any internal data transfer. This function requires
|
||||||
|
that all hardware and software within the platform provide notification of potential errors and that
|
||||||
|
these errors are routed to standard error logs that are checked by the Platform Provider.
|
||||||
|
Refines into requirements: FREQ 40 to 54.
|
||||||
|
2.4.3 Use Case: Manage Infrastructure
|
||||||
|
ID: UC6
|
||||||
|
Refines: SUB-GOAL 2: City data is managed in a safe and intelligent manner
|
||||||
|
Pre-condition: The platform is available
|
||||||
|
Actors: Urban Platform
|
||||||
|
Rationale: Manage infrastructure provides the services and functions for the overall operation of
|
||||||
|
the urban platform. Administration functions include monitoring quality of service agreements,
|
||||||
|
auditing data publication to ensure that they meet archive standards, and maintaining configuration
|
||||||
|
management of system hardware and software. In overall, it provides system engineering
|
||||||
|
functions to monitor and improve platform operations, and to inventory, report on, and
|
||||||
|
migrate/update the contents of the platforms’ databases.
|
||||||
|
Refines into requirements: FREQ 55 to 62.
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 22
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Use Case Basic Interactions and Responses
|
||||||
|
1. Platform keeps monitoring services at run-time to ensure operation
|
||||||
|
and integrity of city data
|
||||||
|
o If system failure, the platform activates mechanisms for recovery
|
||||||
|
UC6. Manage based on pre-defined rules
|
||||||
|
Infrastructure o Platform logs issue and issue alert messages to platform providers
|
||||||
|
2. Platform logs operation capabilities (e.g. performance, mean of time
|
||||||
|
failure, issues, etc.)
|
||||||
|
|
||||||
|
|
||||||
|
2.4.4 Functional Requirements
|
||||||
|
|
||||||
|
Req. ID UC. ID Description Priority Domain
|
||||||
|
A minimal set of identifying information/metadata concerning data Business Needs,
|
||||||
|
FREQ.28 UC4 Must
|
||||||
|
publication submission must be recorded. Platform
|
||||||
|
Stores and tracks versions of data. Links /connections between
|
||||||
|
FREQ.29 UC4 Must City Data, Platform
|
||||||
|
versions are created and maintained.
|
||||||
|
|
||||||
|
FREQ.30 UC4 Converts data to accepted file formats Must City Data, Platform
|
||||||
|
|
||||||
|
Keep sensitive information secured and accessible only to authorized
|
||||||
|
FREQ.31 UC4 Must City Data, Platform
|
||||||
|
users
|
||||||
|
|
||||||
|
FREQ.32 UC4 Keep user’s personal information protected Should City Data, Platform
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.33 UC4 Keep city data and meta-data secured Must Platform Needs
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.34 UC4 Enable privacy preserving mechanisms associated to data Must Platform Needs
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.35 UC4 Model data in accordance with defined standards Must City Data, Platform
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.36 UC4 Support the use of ontologies and semantic modelling of city data Could City Data
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.37 UC4 Support database-level provenance annotation Should City Data
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.38 UC4 Support data-level provenance annotation Should City Data
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.39 UC4 Enable data to be encrypted Should Platform Needs
|
||||||
|
|
||||||
|
System must have the ability to search and display metadata, preferably
|
||||||
|
City Data, Platform
|
||||||
|
FREQ.40 UC5 in a user-conformable, human readable display as well as in its native Must
|
||||||
|
Needs
|
||||||
|
format for machine harvesting and manipulation.
|
||||||
|
Controls access to data in the repository based on multiple permission
|
||||||
|
City Data, Platform
|
||||||
|
FREQ.41 UC5 levels. These permission levels determine the create/edit/read/delete Should
|
||||||
|
Needs
|
||||||
|
privileges granted users.
|
||||||
|
Access rights and conditions of use will be held for each data and its City Data, Platform
|
||||||
|
FREQ.42 UC5 Should
|
||||||
|
related metadata. Needs
|
||||||
|
Access rights and conditions can be inherited from a parent data to any City Data, Platform
|
||||||
|
FREQ.43 UC5 Could
|
||||||
|
data designated as a child data (derived information). Needs
|
||||||
|
Access rights and conditions of use will be machine readable and City Data, Platform
|
||||||
|
FREQ.44 UC5 Should
|
||||||
|
actionable. Needs
|
||||||
|
Access mechanisms must be sufficiently granular to allow the Business Needs, City
|
||||||
|
FREQ.45 UC5 identification of individual users, in order to maintain audit logs of actions Should
|
||||||
|
Data, Platform
|
||||||
|
performed by users.
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 23
|
||||||
|
|
||||||
|
|
||||||
|
Maintains the integrity of the database which contains both metadata
|
||||||
|
FREQ.46 UC5 and system information. Must Platform Needs
|
||||||
|
|
||||||
|
Provides internal validation such as referential integrity of the contents of City Data, Platform
|
||||||
|
FREQ.47 UC5 the database. Must
|
||||||
|
Needs
|
||||||
|
Creates and maintains schema definitions required to support data
|
||||||
|
FREQ.48 UC5 management functions. Must Platform Needs
|
||||||
|
|
||||||
|
Monitors and ensures that data and metadata are not corrupted during
|
||||||
|
FREQ.49 UC5 transfers. Must Platform Needs
|
||||||
|
|
||||||
|
Provides statistically acceptable assurance that no components of the
|
||||||
|
FREQ.50 UC5 data are corrupted during any internal data transfer. Must Platform Needs
|
||||||
|
|
||||||
|
Performs routine and special data integrity checking for each dataset
|
||||||
|
FREQ.51 UC5 and generates error reports. Must Platform Needs
|
||||||
|
|
||||||
|
Provides disaster recovery capabilities including data backup, off-site
|
||||||
|
FREQ.52 UC5 data storage, data recovery, etc. Must Platform Needs
|
||||||
|
|
||||||
|
Refresh/replace data without service interruption, and update
|
||||||
|
FREQ.53 UC5 corresponding metadata as appropriate. Must Platform Needs
|
||||||
|
|
||||||
|
Ensure that any associated unique identifiers of the updated data are not
|
||||||
|
FREQ.54 UC5 altered. Must Platform Needs
|
||||||
|
|
||||||
|
Audits submissions to ensure that they meet archive/repository
|
||||||
|
FREQ.55 UC6 standards. Must Platform Needs
|
||||||
|
|
||||||
|
Maintains configuration management of the system hardware and
|
||||||
|
FREQ.56 UC6 software. Must Platform Needs
|
||||||
|
|
||||||
|
Has capability to inventory, report on and migrate the contents of the
|
||||||
|
FREQ.57 UC6 repository. Must Platform Needs
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.58 UC6 Ensures data integrity for version upgrades and format migration. Must Platform Needs
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.59 UC6 Monitors functionality of the entire repository. Must Platform Needs
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.60 UC6 Maintains integrity of system configuration. Must Platform Needs
|
||||||
|
|
||||||
|
Audits system operations, performance and usage.
|
||||||
|
FREQ.61 UC6 Must Platform Needs
|
||||||
|
|
||||||
|
Provides platform performance information and database holdings
|
||||||
|
FREQ.62 UC6 inventory reports Must Platform Needs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
2.5 SUB-GOAL 3: City data is orchestrated in a marketplace
|
||||||
|
Rationale: The urban platform enables users to consume and publish data in a secure and privacy
|
||||||
|
protected manner.
|
||||||
|
Drivers: Ensure data is secured and the identity of users are preserved
|
||||||
|
Actions: For Sub-Goal 3 to be maintained in the long-run it requires the efficient realisation of use
|
||||||
|
cases: “Commercialise City Data” and “Commercialise Data Services”, as shown in Figure 7.
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 24
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,700 @@
|
|||||||
|
city data via data API’s 5. Platform quickly process user’s request for data publication
|
||||||
|
6. Platform validates data submitted
|
||||||
|
o If valid data, platform acknowledges data publication has
|
||||||
|
been successful
|
||||||
|
o If non-valid data, platform shows error message and returns
|
||||||
|
to step 1
|
||||||
|
End of data publication
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 18
|
||||||
|
|
||||||
|
|
||||||
|
2.3.3 Use Case: Manage Resources
|
||||||
|
ID: UC3
|
||||||
|
Refines: GOAL 1: City data is collected in an intelligent manner
|
||||||
|
Pre-condition: User successfully authenticates in the platform
|
||||||
|
Actors: City data publisher
|
||||||
|
Rationale: Manage resources provides the services and functions for updating, maintaining and
|
||||||
|
accessing both data and metadata, as well as tracking the usage of resources by users. Ideally
|
||||||
|
the owners of the resources should be the only authorised user to manage resources, and other
|
||||||
|
authorised users can track the usage of the resources in the platform. The platform must provide a
|
||||||
|
database update response indicating the status of the update, avoid update errors to be
|
||||||
|
propagated in the platform, and should keep an audit trail of all actions to enable rollback. Data
|
||||||
|
usage tracking includes performing queries on the data management data to generate result sets,
|
||||||
|
and producing reports from these result sets.
|
||||||
|
Specialised Use Cases: The Use Case Manage Resources data is distinguished into two
|
||||||
|
specialised Use Cases: “User manages resources (UC3.1)” and “User tracks resources usage
|
||||||
|
(UC3.2)”.
|
||||||
|
Subordinated Use Cases: “Transmit Data (UC5)”
|
||||||
|
Refines into requirements: FREQ.27 to FREQ.25.
|
||||||
|
|
||||||
|
|
||||||
|
Specialised Use Cases Basic Interactions and Responses
|
||||||
|
1. Platform provides user with an interface for resources
|
||||||
|
management (e.g. data and metadata, data usage)
|
||||||
|
2. User chooses to edit or delete data
|
||||||
|
3. If edit, user revise metadata associated with the data (license,
|
||||||
|
provenance, ownership, access-control, semantics);
|
||||||
|
UC3.1. User manages 4. If delete, user selects dataset(s) to be removed
|
||||||
|
resources 5. User confirms action
|
||||||
|
6. Platform quickly process user’s request
|
||||||
|
7. Platform confirms execution of request
|
||||||
|
o If valid request, platform acknowledges request has been
|
||||||
|
processed successfully
|
||||||
|
o If non-valid request, platform returns to step 1.
|
||||||
|
8. End of resources management
|
||||||
|
1. Platform provides user with an interface for resources
|
||||||
|
management (e.g. data and metadata, data usage)
|
||||||
|
2. User chooses to visualise usage information of a dataset
|
||||||
|
UC3.2. User tracks 3. Platform quickly process user’s request for data usage
|
||||||
|
resources usage information
|
||||||
|
4. Platform provides user with statistical information about data
|
||||||
|
usage and data users anonymised information
|
||||||
|
5. End of data usage tracking.
|
||||||
|
|
||||||
|
|
||||||
|
2.3.4 Functional Requirements
|
||||||
|
|
||||||
|
Req. ID UC. ID Description Priority Domain
|
||||||
|
Societal Needs,
|
||||||
|
FREQ.1 UC1 Allow data publishers to register to submit data for publication Must
|
||||||
|
Platform
|
||||||
|
Tracks data publication agreements between Data and Platform Business Needs,
|
||||||
|
FREQ.2 UC1 Must
|
||||||
|
Providers Platform
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 19
|
||||||
|
|
||||||
|
|
||||||
|
Store terms of agreements, and use them to monitor/review/process
|
||||||
|
FREQ.3 UC1 Must City Data, Platform
|
||||||
|
data submissions.
|
||||||
|
Able to add and edit terms of agreement, based on access of level of Business Needs,
|
||||||
|
FREQ.4 UC1 Must
|
||||||
|
user. Platform
|
||||||
|
|
||||||
|
FREQ.5 UC1 Data publications are managed and monitored Must City Data, Platform
|
||||||
|
|
||||||
|
Allow authenticated users from across different organisations to City Data, Platform,
|
||||||
|
FREQ.6 UC2 Must
|
||||||
|
publish city data Business Needs
|
||||||
|
Provide authorization mechanisms for users and sensors to publish
|
||||||
|
FREQ.7 UC2 Must City Data, Platform
|
||||||
|
city data
|
||||||
|
City Data, Platform,
|
||||||
|
FREQ.9 UC2 Provide mechanisms for static data publication Must
|
||||||
|
Business Needs
|
||||||
|
City Data, Platform,
|
||||||
|
FREQ.10 UC2 Provide mechanisms for real-time data publication Must
|
||||||
|
Business Needs
|
||||||
|
|
||||||
|
FREQ.11 UC2 Enable the publication of metadata Must City Data, Platform
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.12 UC2 Maintain temporal information about the data Must City Data, Platform
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.13 UC2 Support sensory data collection Must City Data, Platform
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.14 UC2 Accepts content in numerous file types/formats Must City Data, Platform
|
||||||
|
|
||||||
|
Prompts a request for resubmission to the data provider if an error of
|
||||||
|
FREQ.15 UC2 Must City Data, Platform
|
||||||
|
data transmission or receipt occurs
|
||||||
|
|
||||||
|
FREQ.16 UC2 Enable the semantic description of connected devices Must City Data, Platform
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.17 UC2 Gather data from authenticated and authorized devices Must City Data, Platform
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.18 UC2 Validates automatically the successful transfer of the data Must City Data, Platform
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.19 UC2 Performs virus checking on data Must City Data, Platform
|
||||||
|
|
||||||
|
Verifies the validity of the submission based on submitter, expected
|
||||||
|
FREQ.20 UC2 Must City Data, Platform
|
||||||
|
format, data quality, and completeness
|
||||||
|
Platform should have built-in checks on the incoming metadata. Data
|
||||||
|
FREQ.21 UC2 not containing the minimally defined set of attributes should be Must City Data, Platform
|
||||||
|
returned to the publisher for metadata enhancement.
|
||||||
|
System should have a user-friendly method of mapping non-standard
|
||||||
|
FREQ.22 UC2 Should City Data, Platform
|
||||||
|
metadata elements into approved standard elements.
|
||||||
|
Once ingested, metadata should be stored in a single common format.
|
||||||
|
FREQ.23 UC2 This format should be one that ensures against data loss, and allows a Must City Data, Platform
|
||||||
|
variety of access/distribution options
|
||||||
|
Data in the repository shall have sufficient technical metadata to
|
||||||
|
FREQ.24 UC2 assure functionality (e.g. viewing and display) to ensure accessibility Must City Data, Platform
|
||||||
|
and reusability.
|
||||||
|
Allows publishers to display and perform manual/visual quality control Business Needs, City
|
||||||
|
FREQ.25 UC2 Could
|
||||||
|
assurance via a user-friendly GUI Data, Platform
|
||||||
|
Business Needs, City
|
||||||
|
FREQ.26 UC2 Any errors shall prompt a request for resubmission of data Should
|
||||||
|
Data, Platform
|
||||||
|
|
||||||
|
FREQ.27 UC3 Enable data providers to manage their resources Must Business Needs
|
||||||
|
|
||||||
|
A minimal set of identifying information/metadata concerning data Business Needs,
|
||||||
|
FREQ.28 UC3 Must
|
||||||
|
publication submission must be recorded Platform
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 20
|
||||||
|
|
||||||
|
|
||||||
|
Stores and tracks versions of data. Links /connections between
|
||||||
|
FREQ.29 UC3 Must City Data, Platform
|
||||||
|
versions are created and maintained
|
||||||
|
Give service and data providers access to anonymized data of the Business Needs
|
||||||
|
FREQ.30 UC3 Should
|
||||||
|
subscribers of their data or services
|
||||||
|
City Data, Platform,
|
||||||
|
FREQ.31 UC3 Enable data providers to maintain and repair data and metadata Should
|
||||||
|
Business Needs
|
||||||
|
Tracks data publication agreements between Data and Platform Business Needs,
|
||||||
|
FREQ.32 UC3 Must
|
||||||
|
Providers Platform
|
||||||
|
Store terms of agreements, and use them to monitor/review/process
|
||||||
|
FREQ.33 UC3 Must City Data, Platform
|
||||||
|
data submissions.
|
||||||
|
Able to add and edit terms of agreement, based on access of level of Business Needs,
|
||||||
|
FREQ.34 UC3 Must
|
||||||
|
user. Platform
|
||||||
|
|
||||||
|
FREQ.35 UC3 Submission volumes and schedules are managed and monitored Must City Data, Platform
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
2.4 SUB-GOAL 2: City data is managed in a safe and intelligent manner
|
||||||
|
Rationale: The urban platform enables users to publish, consume and commercialise data, as well
|
||||||
|
as deploy and manage services all in a secure and privacy protected manner.
|
||||||
|
|
||||||
|
Achieve [City data is exploited
|
||||||
|
to its full effect]
|
||||||
|
Goal
|
||||||
|
co-ena bles
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Maintain [Resources are managed in a
|
||||||
|
safe and intelligent manner]
|
||||||
|
S ub-Goal 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Achieve [Store Data] Achieve [Transmit Data] Achieve [Manage Infrastructure]
|
||||||
|
UC4 UC5 UC6
|
||||||
|
|
||||||
|
|
||||||
|
Figure 6. Sub-Goal 2 “City data is managed in a safe and intelligent manner” refinement.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Drivers: Ensure data is secured and the identity of users are preserved
|
||||||
|
Actions: For Sub-Goal 2 to be maintained in the long-run it requires the efficient realisation of use
|
||||||
|
cases: “Store City Data” and “Retrieve and Transmit City Data”, as shown in Figure 6.
|
||||||
|
|
||||||
|
|
||||||
|
2.4.1 Use Case: Store City Data
|
||||||
|
ID: UC4
|
||||||
|
Refines: SUB-GOAL 2: City data is managed in a safe and intelligent manner
|
||||||
|
Pre-condition: Data is successfully published in the platform
|
||||||
|
Actors: Urban Platform
|
||||||
|
Rationale: When data is successfully submitted (either via APIs or manual upload), it is
|
||||||
|
processed/prepared for storage into the platform’s database. This procedure will include the
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 21
|
||||||
|
|
||||||
|
|
||||||
|
generation of unique identifiers to the database, enrichment with ontologies (when applicable),
|
||||||
|
encrypted (when applicable), signed with digital certificates (when applicable) to ensure that the
|
||||||
|
data conforms to the platform data formatting, standards, security and regulation. Data may be
|
||||||
|
converted to accepted formats, as needed (e.g. graph model). A primary goal of the conversion of
|
||||||
|
content for the platform is the preservation of the content. Priority will be given to preserving the
|
||||||
|
data accordingly to the policies defined in section (2.6.2). Access-control levels and license models
|
||||||
|
are associated to data which is subject to restrictions relating to access and conditions of use.
|
||||||
|
Refines into requirements: FREQ 28 – FREQ 39.
|
||||||
|
|
||||||
|
Use Case Basic Interactions and Responses
|
||||||
|
1. Platform mechanisms converts submitted data into a standard format
|
||||||
|
2. Security enforcement (e.g. anonymisation, cryptography) is placed on
|
||||||
|
sensitive information.
|
||||||
|
UC4. Store City 3. Platform associates with datasets the access-control definitions set by
|
||||||
|
Data owner of resources.
|
||||||
|
4. Data is enriched with semantics and is associated with other datasets
|
||||||
|
5. Platform stores data in a scalable and secure database.
|
||||||
|
6. End of data storage.
|
||||||
|
|
||||||
|
|
||||||
|
2.4.2 Use Case: Transmit Data
|
||||||
|
ID: UC5
|
||||||
|
Refines: SUB-GOAL 2: City data is managed in a safe and intelligent manner
|
||||||
|
Pre-condition: Data is successfully published in the platform
|
||||||
|
Actors: Urban Platform
|
||||||
|
Rationale: The platform accepts data retrieval request, validates user’s rights to access the data,
|
||||||
|
retrieves city data from data storage, and moves a copy of the data to the relevant platform
|
||||||
|
component for further processing. If special processing is required, the retrieval function accesses
|
||||||
|
data in staging storage and applies the requested processes. The types of operations, which may
|
||||||
|
be carried out, include sub-sampling in temporal or spatial dimensions, conversions between
|
||||||
|
different data types or output formats, and other specialized processing (e.g., data visualisation).
|
||||||
|
Once it is finalised data will be sent to the appropriate delivery channels (e.g. API’s, GUI). It also
|
||||||
|
encompasses function to verify corruption during any internal data transfer. This function requires
|
||||||
|
that all hardware and software within the platform provide notification of potential errors and that
|
||||||
|
these errors are routed to standard error logs that are checked by the Platform Provider.
|
||||||
|
Refines into requirements: FREQ 40 to 54.
|
||||||
|
2.4.3 Use Case: Manage Infrastructure
|
||||||
|
ID: UC6
|
||||||
|
Refines: SUB-GOAL 2: City data is managed in a safe and intelligent manner
|
||||||
|
Pre-condition: The platform is available
|
||||||
|
Actors: Urban Platform
|
||||||
|
Rationale: Manage infrastructure provides the services and functions for the overall operation of
|
||||||
|
the urban platform. Administration functions include monitoring quality of service agreements,
|
||||||
|
auditing data publication to ensure that they meet archive standards, and maintaining configuration
|
||||||
|
management of system hardware and software. In overall, it provides system engineering
|
||||||
|
functions to monitor and improve platform operations, and to inventory, report on, and
|
||||||
|
migrate/update the contents of the platforms’ databases.
|
||||||
|
Refines into requirements: FREQ 55 to 62.
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 22
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Use Case Basic Interactions and Responses
|
||||||
|
1. Platform keeps monitoring services at run-time to ensure operation
|
||||||
|
and integrity of city data
|
||||||
|
o If system failure, the platform activates mechanisms for recovery
|
||||||
|
UC6. Manage based on pre-defined rules
|
||||||
|
Infrastructure o Platform logs issue and issue alert messages to platform providers
|
||||||
|
2. Platform logs operation capabilities (e.g. performance, mean of time
|
||||||
|
failure, issues, etc.)
|
||||||
|
|
||||||
|
|
||||||
|
2.4.4 Functional Requirements
|
||||||
|
|
||||||
|
Req. ID UC. ID Description Priority Domain
|
||||||
|
A minimal set of identifying information/metadata concerning data Business Needs,
|
||||||
|
FREQ.28 UC4 Must
|
||||||
|
publication submission must be recorded. Platform
|
||||||
|
Stores and tracks versions of data. Links /connections between
|
||||||
|
FREQ.29 UC4 Must City Data, Platform
|
||||||
|
versions are created and maintained.
|
||||||
|
|
||||||
|
FREQ.30 UC4 Converts data to accepted file formats Must City Data, Platform
|
||||||
|
|
||||||
|
Keep sensitive information secured and accessible only to authorized
|
||||||
|
FREQ.31 UC4 Must City Data, Platform
|
||||||
|
users
|
||||||
|
|
||||||
|
FREQ.32 UC4 Keep user’s personal information protected Should City Data, Platform
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.33 UC4 Keep city data and meta-data secured Must Platform Needs
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.34 UC4 Enable privacy preserving mechanisms associated to data Must Platform Needs
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.35 UC4 Model data in accordance with defined standards Must City Data, Platform
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.36 UC4 Support the use of ontologies and semantic modelling of city data Could City Data
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.37 UC4 Support database-level provenance annotation Should City Data
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.38 UC4 Support data-level provenance annotation Should City Data
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.39 UC4 Enable data to be encrypted Should Platform Needs
|
||||||
|
|
||||||
|
System must have the ability to search and display metadata, preferably
|
||||||
|
City Data, Platform
|
||||||
|
FREQ.40 UC5 in a user-conformable, human readable display as well as in its native Must
|
||||||
|
Needs
|
||||||
|
format for machine harvesting and manipulation.
|
||||||
|
Controls access to data in the repository based on multiple permission
|
||||||
|
City Data, Platform
|
||||||
|
FREQ.41 UC5 levels. These permission levels determine the create/edit/read/delete Should
|
||||||
|
Needs
|
||||||
|
privileges granted users.
|
||||||
|
Access rights and conditions of use will be held for each data and its City Data, Platform
|
||||||
|
FREQ.42 UC5 Should
|
||||||
|
related metadata. Needs
|
||||||
|
Access rights and conditions can be inherited from a parent data to any City Data, Platform
|
||||||
|
FREQ.43 UC5 Could
|
||||||
|
data designated as a child data (derived information). Needs
|
||||||
|
Access rights and conditions of use will be machine readable and City Data, Platform
|
||||||
|
FREQ.44 UC5 Should
|
||||||
|
actionable. Needs
|
||||||
|
Access mechanisms must be sufficiently granular to allow the Business Needs, City
|
||||||
|
FREQ.45 UC5 identification of individual users, in order to maintain audit logs of actions Should
|
||||||
|
Data, Platform
|
||||||
|
performed by users.
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 23
|
||||||
|
|
||||||
|
|
||||||
|
Maintains the integrity of the database which contains both metadata
|
||||||
|
FREQ.46 UC5 and system information. Must Platform Needs
|
||||||
|
|
||||||
|
Provides internal validation such as referential integrity of the contents of City Data, Platform
|
||||||
|
FREQ.47 UC5 the database. Must
|
||||||
|
Needs
|
||||||
|
Creates and maintains schema definitions required to support data
|
||||||
|
FREQ.48 UC5 management functions. Must Platform Needs
|
||||||
|
|
||||||
|
Monitors and ensures that data and metadata are not corrupted during
|
||||||
|
FREQ.49 UC5 transfers. Must Platform Needs
|
||||||
|
|
||||||
|
Provides statistically acceptable assurance that no components of the
|
||||||
|
FREQ.50 UC5 data are corrupted during any internal data transfer. Must Platform Needs
|
||||||
|
|
||||||
|
Performs routine and special data integrity checking for each dataset
|
||||||
|
FREQ.51 UC5 and generates error reports. Must Platform Needs
|
||||||
|
|
||||||
|
Provides disaster recovery capabilities including data backup, off-site
|
||||||
|
FREQ.52 UC5 data storage, data recovery, etc. Must Platform Needs
|
||||||
|
|
||||||
|
Refresh/replace data without service interruption, and update
|
||||||
|
FREQ.53 UC5 corresponding metadata as appropriate. Must Platform Needs
|
||||||
|
|
||||||
|
Ensure that any associated unique identifiers of the updated data are not
|
||||||
|
FREQ.54 UC5 altered. Must Platform Needs
|
||||||
|
|
||||||
|
Audits submissions to ensure that they meet archive/repository
|
||||||
|
FREQ.55 UC6 standards. Must Platform Needs
|
||||||
|
|
||||||
|
Maintains configuration management of the system hardware and
|
||||||
|
FREQ.56 UC6 software. Must Platform Needs
|
||||||
|
|
||||||
|
Has capability to inventory, report on and migrate the contents of the
|
||||||
|
FREQ.57 UC6 repository. Must Platform Needs
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.58 UC6 Ensures data integrity for version upgrades and format migration. Must Platform Needs
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.59 UC6 Monitors functionality of the entire repository. Must Platform Needs
|
||||||
|
|
||||||
|
|
||||||
|
FREQ.60 UC6 Maintains integrity of system configuration. Must Platform Needs
|
||||||
|
|
||||||
|
Audits system operations, performance and usage.
|
||||||
|
FREQ.61 UC6 Must Platform Needs
|
||||||
|
|
||||||
|
Provides platform performance information and database holdings
|
||||||
|
FREQ.62 UC6 inventory reports Must Platform Needs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
2.5 SUB-GOAL 3: City data is orchestrated in a marketplace
|
||||||
|
Rationale: The urban platform enables users to consume and publish data in a secure and privacy
|
||||||
|
protected manner.
|
||||||
|
Drivers: Ensure data is secured and the identity of users are preserved
|
||||||
|
Actions: For Sub-Goal 3 to be maintained in the long-run it requires the efficient realisation of use
|
||||||
|
cases: “Commercialise City Data” and “Commercialise Data Services”, as shown in Figure 7.
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 24
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Achieve [City data is exploited
|
||||||
|
to its full effect]
|
||||||
|
Goal
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
co-ena bles
|
||||||
|
Maintain [City data is orchestrated in
|
||||||
|
a marketplace]
|
||||||
|
S ub-Goal 3
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Achieve [Commercialise Data
|
||||||
|
Achieve [Commercialise City Data]
|
||||||
|
Services]
|
||||||
|
UC7 UC8
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Figure 7. Sub-Goal 3 “City data is orchestrated in a marketplace” refinement.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
2.5.1 Use Case: Commercialise City Data
|
||||||
|
ID: UC7
|
||||||
|
Refines: SUB-GOAL 3: City data is orchestrated in a marketplace
|
||||||
|
Pre-condition: Data is successfully published in the platform, both publisher and consumers of
|
||||||
|
city data are authenticated in the platform, and there are billing capabilities available.
|
||||||
|
Actors: Data Publishers, Data Consumers
|
||||||
|
Rationale: The providers of city data can commercialise city data based on the policies and
|
||||||
|
financial models defined in the platform. After publishing their data, publishers can define which
|
||||||
|
data can be available as open data and which data should be available with the payment of a
|
||||||
|
subscription fee. Once publishers define which data is to be commercially exploited, the platform
|
||||||
|
will associate the data with their respective financial models and let it ready for subscription. City
|
||||||
|
data consumer chooses which data to purchase and is redirected to a billing interface where the
|
||||||
|
subscription payment is taken. The platform must provide an update response indicating the status
|
||||||
|
of the payment. If successful, data is ready available to be consumed by humans and machines,
|
||||||
|
otherwise the user can re-try the payment or cancel transaction.
|
||||||
|
Commercialise city data also involves the function of managing commercial data. It provides
|
||||||
|
services and functions for updating, maintaining and accessing both data and its respective
|
||||||
|
commercial transactions. Furthermore, it enables data providers to track the usage of commercial
|
||||||
|
data by users. Ideally the owners of the data should be the only authorised user to manage
|
||||||
|
resources, and other authorised users can track the usage of the data in the platform. Data usage
|
||||||
|
tracking includes performing queries on the data management data to generate result sets, and
|
||||||
|
producing reports from these result sets. Data consumers are provided with functions which enable
|
||||||
|
them to manage their subscriptions and financial transactions on the platform. These functions
|
||||||
|
include updating, maintaining and accessing financial transactions. For all these functions and
|
||||||
|
services, the platform must provide a database update response indicating the status of the
|
||||||
|
update, avoid update errors to be propagated in the platform, and should keep an audit trail of all
|
||||||
|
actions to enable rollback.
|
||||||
|
Specialised Use Cases: The Use Case Commercialise City Data is distinguished into four
|
||||||
|
specialised Use Cases: “Commercialise Data (UC7.1)”, “Consume Commercial City Data (UC7.2)”,
|
||||||
|
“Manage Commercial Data (UC7.3)” and “Manage Data Subscription (UC7.4)”.
|
||||||
|
Refines into requirements: FREQ 63 to 68.
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 25
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Use Case Basic Interactions and Responses
|
||||||
|
1. User selects the data to be commercialised
|
||||||
|
2. User selects the commercial model for data consumption
|
||||||
|
UC7.1. 3. Platform validates selection
|
||||||
|
Commercialise 4. Platform associates data to subscription model
|
||||||
|
Data 5. Platform releases data for commercial exploitation in the marketplace
|
||||||
|
6. End of data commercialisation set up.
|
||||||
|
1. User selects the data to be subscribed to
|
||||||
|
2. User request subscription to data
|
||||||
|
UC7.2. 3. Platform validates selection
|
||||||
|
Consume 4. Platform redirects user to billing system
|
||||||
|
Proprietary 5. Billing system deals with user request
|
||||||
|
Data o If successful, user is redirected to a GUI where data is ready to use
|
||||||
|
o If unsuccessful, user can try payment again or cancel request
|
||||||
|
2. End of data subscription.
|
||||||
|
1. Platform provides user with an interface for commercial data
|
||||||
|
management
|
||||||
|
2. User chooses to edit or delete commercial data
|
||||||
|
o If edit, user revise commercial models, licenses, access-control,
|
||||||
|
semantics;
|
||||||
|
o If delete, user selects dataset(s) to be removed (following policies
|
||||||
|
UC7.3. Manage defined in the platform for data removal)
|
||||||
|
commercial 3. User confirms action
|
||||||
|
Data 4. Platform promptly process user’s request
|
||||||
|
5. Platform confirms execution of request
|
||||||
|
o If valid request, platform acknowledges request has been
|
||||||
|
processed successfully
|
||||||
|
o If non-valid request, platform returns to step 1.
|
||||||
|
6. End of resources management
|
||||||
|
1. Platform provides user with an interface for data subscription
|
||||||
|
management
|
||||||
|
2. User chooses to edit or cancel data subscription
|
||||||
|
o If edit, user revise payment and subscription timeframe;
|
||||||
|
o If cancel, user selects dataset(s) to have subscription cancelled
|
||||||
|
UC7.4. Manage (following policies defined in the platform for data subscription)
|
||||||
|
data 3. User confirms action
|
||||||
|
subscription 4. Platform promptly process user’s request
|
||||||
|
5. Platform confirms execution of request
|
||||||
|
o If valid request, platform updates acknowledges request has been
|
||||||
|
processed successfully
|
||||||
|
o If non-valid request, platform returns to step 1.
|
||||||
|
6. End of data subscription management
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
2.5.2 Use Case: Commercialise Data Services
|
||||||
|
ID: UC8
|
||||||
|
Refines: SUB-GOAL 3: City data is orchestrated in a marketplace
|
||||||
|
Pre-condition: Data is successfully published in the platform, both publisher and consumers of
|
||||||
|
city data are authenticated in the platform, and there are billing capabilities available.
|
||||||
|
Actors: Data Service Providers, Data Publishers and Consumers
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 26
|
||||||
|
|
||||||
|
|
||||||
|
Rationale: After deploying data services in the platform, the providers of data services can choose
|
||||||
|
to commercialise services based on the policies and financial models defined in the platform. Once
|
||||||
|
data service providers define which service(s) is (are) to be commercially exploited, the platform
|
||||||
|
will associate the services with their respective financial models and let available in the platform
|
||||||
|
applications module ready for use. User (either publisher or consumer) chooses which data
|
||||||
|
services to use, and in case a charged service is selected the platform redirects the user to a
|
||||||
|
billing interface where the payment is taken. The platform must provide an update response
|
||||||
|
indicating the status of the payment. If successful, service is ready available to be used, otherwise
|
||||||
|
the user can re-try the payment or cancel transaction. Note that data service owners should be
|
||||||
|
able to waive the payment of tariff to certain users’ categories.
|
||||||
|
Data services providers are offered with functions to manage their commercial services. The
|
||||||
|
platform provides functions for updating, maintaining and accessing both service and its respective
|
||||||
|
commercial transactions. Furthermore, it enables data services providers to track the usage of
|
||||||
|
services by users. Services usage tracking includes performing queries on the platform to
|
||||||
|
generate result sets, and producing reports from these result sets. The consumers of data services
|
||||||
|
are provided with functions which enable them to manage their subscriptions and financial
|
||||||
|
transactions. These functions include updating, maintaining and accessing financial transactions.
|
||||||
|
For all these functions and services, the platform must provide a database update response
|
||||||
|
indicating the status of the update, avoid update errors to be propagated in the platform, and
|
||||||
|
should keep an audit trail of all actions to enable rollback.
|
||||||
|
Specialised Use Cases: The Use Case Commercialise Data Services is distinguished into four
|
||||||
|
specialised Use Cases: “Commercialise Data Services (UC8.1)”, “Consume Data Services
|
||||||
|
(UC8.2)”, “Manage Commercial Services (UC8.3)” and “Manage Services Subscription (UC8.4)”.
|
||||||
|
Refines into requirements: FREQ 68 to 73.
|
||||||
|
|
||||||
|
Use Case Basic Interactions and Responses
|
||||||
|
1. User selects the data services to be commercialised
|
||||||
|
2. User selects the commercial model for data service usage based on the
|
||||||
|
category of users
|
||||||
|
UC8.1. 3. Platform validates selection
|
||||||
|
Commercialise 4. Platform associates data services to subscription model
|
||||||
|
Data Services 5. Platform enables data service to be commercially exploited in the
|
||||||
|
marketplace
|
||||||
|
6. End of services commercialisation set up.
|
||||||
|
1. User selects the data service to be subscribed to
|
||||||
|
2. User request subscription to service
|
||||||
|
3. Platform validates selection
|
||||||
|
UC8.2. 4. Platform validates user’s category its respective commercial models
|
||||||
|
Consume Data 4. If applicable, platform redirects user to billing system
|
||||||
|
Services 5. Billing system deals with user’s request
|
||||||
|
o If successful, user is redirected to a GUI where data is ready to use
|
||||||
|
o If unsuccessful, user can try payment again or cancel request
|
||||||
|
6. End of data subscription.
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 27
|
||||||
|
|
||||||
|
|
||||||
|
1. Platform provides user with an interface for commercial data
|
||||||
|
management
|
||||||
|
2. User chooses to edit or delete commercial data
|
||||||
|
o If edit, user revise commercial models, licenses, access-control,
|
||||||
|
semantics;
|
||||||
|
o If delete, user selects dataset(s) to be removed (following policies
|
||||||
|
UC8.3. Manage defined in the platform for data removal)
|
||||||
|
commercial 3. User confirms action
|
||||||
|
services 4. Platform promptly process user’s request
|
||||||
|
5. Platform confirms execution of request
|
||||||
|
o If valid request, platform acknowledges request has been
|
||||||
|
processed successfully
|
||||||
|
o If non-valid request, platform returns to step 1.
|
||||||
|
6. End of resources management
|
||||||
|
1. Platform provides user with an interface for data subscription
|
||||||
|
management
|
||||||
|
2. User chooses to edit or cancel data subscription
|
||||||
|
o If edit, user revise payment and subscription timeframe;
|
||||||
|
o If cancel, user selects dataset(s) to have subscription cancelled
|
||||||
|
UC8.4. Manage (following policies defined in the platform for data subscription)
|
||||||
|
services 3. User confirms action
|
||||||
|
subscription 4. Platform promptly process user’s request
|
||||||
|
5. Platform confirms execution of request
|
||||||
|
o If valid request, platform updates acknowledges request has been
|
||||||
|
processed successfully
|
||||||
|
o If non-valid request, platform returns to step 1.
|
||||||
|
6. End of data subscription management
|
||||||
|
|
||||||
|
|
||||||
|
2.5.3 Functional Requirements
|
||||||
|
|
||||||
|
Req. ID UC. ID Description Priority Domain
|
||||||
|
City Data, Platform,
|
||||||
|
FREQ.63 UC7 Support the commercialization of city data Should Business Needs
|
||||||
|
City Data, Platform,
|
||||||
|
FREQ.64 UC7 Enable users to subscribe to city data through the payment of a tariff Should Business Needs
|
||||||
|
City Data, Platform,
|
||||||
|
FREQ.65 UC7 Enable users to manage their data subscriptions Should Business
|
||||||
|
Provide platform providers mechanisms to define the terms and
|
||||||
|
FREQ.66 UC7 Must Platform Needs
|
||||||
|
conditions for platform data usage
|
||||||
|
Enable data providers to manage the subscription models of their City Data, Platform,
|
||||||
|
FREQ.67 UC7 Should
|
||||||
|
data Business
|
||||||
|
UC7/ City Data, Platform,
|
||||||
|
FREQ.68 Utilise secure and reliable billing and payment management systems Must
|
||||||
|
UC8 Business
|
||||||
|
City Data, Platform,
|
||||||
|
FREQ.69 UC8 Support the commercialization of data services Should Business Needs
|
||||||
|
Enable data providers to manage the commercial models of their City Data, Platform,
|
||||||
|
FREQ.70 UC8 Should
|
||||||
|
services Business Needs
|
||||||
|
Provide service providers mechanisms to define the terms and City Data, Platform,
|
||||||
|
FREQ.71 UC8 Should
|
||||||
|
conditions of platform services Business Needs
|
||||||
|
Allow users to pay a tariff for using certain advanced services (e.g. City Data, Platform,
|
||||||
|
FREQ.72 UC8 Should
|
||||||
|
Data manipulation, enrichment) Business Needs
|
||||||
|
City Data, Platform,
|
||||||
|
FREQ.73 UC8 Enable users to manage their data services subscriptions Should Business Needs
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 28
|
||||||
|
|
||||||
|
|
||||||
|
2.6 SUB-GOAL 4: City data is offered in an accessible manner
|
||||||
|
Rationale: The urban platform provides city data in both human and machine (e.g. sensors,
|
||||||
|
actuators, systems) readable and understandable formats.
|
||||||
|
Drivers: Ensure data understandability and machine-to-machine data transaction.
|
||||||
|
Actions: For Sub-Goal 3 to be maintained in the long-run it requires the efficient realisation of use
|
||||||
|
cases: “Register Consumer”, “Discover City Data”, and “Consume City Data” as shown in Figure 8.
|
||||||
|
|
||||||
|
Achieve [City data is exploited
|
||||||
|
to its full effect]
|
||||||
|
Goal
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
co-ena bles
|
||||||
|
Maintain [City data is offered in an
|
||||||
|
accessible manner]
|
||||||
|
S ub-Goal 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Achieve [Register Consumer] Achieve [Discover City Data] Achieve [Consume City Data]
|
||||||
|
UC9 UC10 UC11
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Figure 8. Sub-Goal 4 “City data is offered in an accessible manner” refinement.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
2.6.1 Use Case: Register Data Consumer
|
||||||
|
ID: UC9
|
||||||
|
Refines: SUB-GOAL 4: City data is offered in an accessible manner
|
||||||
|
Pre-condition: User is not logged in the platform
|
||||||
|
Actors: Data Consumers
|
||||||
|
Rationale: Data Consumers can register in the platform and request approval to consume city data
|
||||||
|
via GUI or APIs. They provide valid registration details (to be defined) and wait for platform to
|
||||||
|
confirm their registration. Users must accept the terms and conditions of platform usage and define
|
||||||
|
how their personal data can be used by the Platform Owner. Users can manage and alter their
|
||||||
|
registration information at any time they want to.
|
||||||
|
Refines into requirements: FREQ 64.
|
||||||
|
|
||||||
|
Use Case Basic Stimulus and Responses
|
||||||
|
1. The platform prompts the user for a username and password or register
|
||||||
|
new account.
|
||||||
|
2. The user selects registration option.
|
||||||
|
3. The platform prompts user for data consumer registration information
|
||||||
|
UC1. Register 4. The user enters in their information.
|
||||||
|
Consumer 5. Platform verifies information and creates account.
|
||||||
|
o If non-valid information, platform shows error message and returns to
|
||||||
|
step 1.
|
||||||
|
6. Platform acknowledges registration has been successful
|
||||||
|
7. End of registration
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 29
|
||||||
|
|
||||||
|
|
||||||
|
2.6.2 Use Case: Discover City Data
|
||||||
|
ID: UC10
|
||||||
|
Refines: SUB-GOAL 4: City data is offered in an accessible manner
|
||||||
|
Pre-condition: User has access to either platform GUI or API
|
||||||
|
Actors: Data Consumers
|
||||||
|
Rationale: Data Consumers can register in the platform and request approval to consume city data
|
||||||
|
via GUI or APIs. They provide valid registration details (to be defined) and wait for platform to
|
||||||
|
confirm their registration.
|
||||||
|
Refines into requirements: FREQ 64.
|
||||||
|
|
||||||
|
Use Case Basic Stimulus and Responses
|
||||||
|
1. Users access specialised data query end-points (e.g. SPARQL)
|
||||||
|
2. Users provides information for pre-defined parameters for search
|
||||||
|
3. Users request data search
|
||||||
|
4. Platform quickly process users request for data
|
||||||
@@ -0,0 +1,604 @@
|
|||||||
|
Consume City o If authentication is successful, users are provided with requested
|
||||||
|
Data via APIs data streams
|
||||||
|
3. Users are provided with requested data via APIs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
2.6.4 Functional Requirements
|
||||||
|
|
||||||
|
Req. ID UC. ID Description Priority Domain
|
||||||
|
Allow users to register to use services and consume proprietary city Societal Needs,
|
||||||
|
FREQ.74 UC9 Should
|
||||||
|
data and open data (optional) Platform
|
||||||
|
Keep sensitive information secured and accessible only to Societal Needs,
|
||||||
|
FREQ.75 UC9 Should
|
||||||
|
authorized users Platform
|
||||||
|
Societal Needs,
|
||||||
|
FREQ.76 UC9 Provide authentication mechanisms for users Must Platform
|
||||||
|
Societal Needs,
|
||||||
|
FREQ.77 UC9 Keep user’s personal information protected Must Platform
|
||||||
|
Allow users to control which data they are willing to provide and how Societal Needs,
|
||||||
|
FREQ.78 UC9 Must
|
||||||
|
their data should be used Platform
|
||||||
|
Societal Needs,
|
||||||
|
FREQ.79 UC10 Allow users to format data in any supported data formats Must
|
||||||
|
Platform
|
||||||
|
The query request may require data to be sourced from different Societal Needs,
|
||||||
|
FREQ.80 UC10 Must
|
||||||
|
storage locations Platform
|
||||||
|
Allows query requests against all metadata used to manage the Societal Needs,
|
||||||
|
FREQ.81 UC10 repository. Should Platform
|
||||||
|
Provide users information about the legal aspects of the data Societal Needs,
|
||||||
|
FREQ.82 UC11 Must
|
||||||
|
(license, ownership) City Data
|
||||||
|
Societal Needs,
|
||||||
|
FREQ.83 UC11 Keeps an audit trail of all actions. Must City Data
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 31
|
||||||
|
|
||||||
|
|
||||||
|
2.7 SUB-GOAL 5: User’s experience is enhanced by the provision of
|
||||||
|
value-added services
|
||||||
|
Rationale: The urban platform enables users to consume and publish data in a secure and privacy
|
||||||
|
protected manner
|
||||||
|
Drivers: Ensure data is secured and the identity of users are preserved
|
||||||
|
Actions: For Sub-Goal 5 to be maintained in the long-run it requires the efficient realisation of use
|
||||||
|
cases: “Deploy Data Services”, “Manage Services”, and “Utilise Data Services” as shown in Figure
|
||||||
|
8.
|
||||||
|
|
||||||
|
Achieve [City data is exploited
|
||||||
|
to its full effect]
|
||||||
|
Goal
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
co-ena bles
|
||||||
|
Maintain [User s experience is enhanced by
|
||||||
|
the provision of value-added services]
|
||||||
|
S ub-Goal 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Achieve [Deploy Data Services] Achieve [Manage Services] Achieve [Utilise Data Services]
|
||||||
|
UC12 UC13 UC14
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Figure 9. Sub-Goal 5 “User’s experience is enhanced by the provision of value-added services” refinement
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
2.7.1 Deploy Data Services
|
||||||
|
ID: UC12
|
||||||
|
Refines: SUB-GOAL 5: User’s experience is enhanced by the provision of value-added services
|
||||||
|
Pre-condition: Data Services Providers are provided with credentials, are authorised to deploy
|
||||||
|
their services in the platform, and have access to technical specifications of the platform interfaces.
|
||||||
|
Actors: Data Services Providers
|
||||||
|
Rationale: Data Services can register in the platform and request approval to deploy services in
|
||||||
|
the platform. They provide valid registration details (to be defined) and wait for registration
|
||||||
|
confirmation. Platform Providers may authorise or not data services providers to offer both open
|
||||||
|
and proprietary services in the platform. Data services providers must formally agree with service
|
||||||
|
deployment agreement with the Urban Platform. This agreement defines terms of the content,
|
||||||
|
policies, regulations, license agreement. The Urban Platform will proactively work with Service
|
||||||
|
Providers to agree on the technical specifications of interfaces and platform openness level.
|
||||||
|
Agreements between Platform and Data Service Providers may be renegotiated on a periodic or
|
||||||
|
ad-hoc basis.
|
||||||
|
Refines into requirements: FREQ.1 to FREQ.5.
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 32
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Use Case Basic Stimulus and Responses
|
||||||
|
1. User authenticates in the platform
|
||||||
|
2. User is provided access to platform interfaces for service deployment
|
||||||
|
3. User deploy services
|
||||||
|
4. Platform checks compatibility and any technical issues arising from the
|
||||||
|
UC12. Deploy new service
|
||||||
|
Services 5. If approved the service is ready to be used and managed in the
|
||||||
|
platform
|
||||||
|
o If deployment is not approved, platform shows error message and
|
||||||
|
returns to step 1.
|
||||||
|
6. End of deployment
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
2.7.2 Use Case: Manage Services
|
||||||
|
ID: UC13
|
||||||
|
Refines: GOAL 5: User’s experience is enhanced by the provision of value-added services
|
||||||
|
Pre-condition: User successfully authenticates in the platform
|
||||||
|
Actors: Data Services Providers
|
||||||
|
Rationale: Manage services provides the functions for updating, maintaining and accessing
|
||||||
|
services as well as tracking their usage by users. Ideally the owners of the services should be the
|
||||||
|
only authorised user to manage them, and other authorised users can track the usage of the
|
||||||
|
services in the platform. In case of updates the platform must log in the database update details
|
||||||
|
and send to service providers a response indicating the status of the update. The platform should
|
||||||
|
also ensure update errors are not propagated nor affect the health of other services provided in the
|
||||||
|
platform, and should keep an audit trail of all actions to enable rollback. Data services usage
|
||||||
|
tracking includes performing queries on the data management data to generate result sets, and
|
||||||
|
producing reports from these result sets. All user’s information provided to service providers must
|
||||||
|
follow regulations of data protection and the user’s defined rules for their data use.
|
||||||
|
Specialised Use Cases: The Use Case Manage Services is distinguished into two specialised
|
||||||
|
Use Cases: “User manages services (UC13.1)” and “User tracks service usage (UC13.2)”.
|
||||||
|
Subordinated Use Cases: “Transmit Data (UC5)”
|
||||||
|
Refines into requirements: FREQ.27 to FREQ.25.
|
||||||
|
|
||||||
|
|
||||||
|
Specialised Use Cases Basic Interactions and Responses
|
||||||
|
1. Platform provides user with an interface for services management
|
||||||
|
2. User chooses to edit or delete services
|
||||||
|
3. If edit, user revise service information (access-control,
|
||||||
|
commercial models, parameters) and deployment;
|
||||||
|
If delete, user selects services to be removed / disabled
|
||||||
|
UC13.1. User manages 4. User confirms action
|
||||||
|
services 5. Platform quickly process user’s request
|
||||||
|
6. Platform confirms execution of request
|
||||||
|
o If valid request, platform acknowledges request has been
|
||||||
|
processed successfully
|
||||||
|
o If non-valid request, platform returns to step 1.
|
||||||
|
7. End of services management
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 33
|
||||||
|
|
||||||
|
|
||||||
|
1. Platform provides user with an interface for services management
|
||||||
|
2. User chooses to visualise usage information of a service
|
||||||
|
3. Platform quickly process user’s request for data usage
|
||||||
|
UC13.2. User tracks information
|
||||||
|
services usage 4. Platform provides user with statistical information about services
|
||||||
|
usage and data users anonymised information
|
||||||
|
5. End of data services tracking.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
2.7.3 Use Case: Utilise Data Services
|
||||||
|
ID: UC2
|
||||||
|
Refines: SUB-GOAL 1 - City data is collected in an intelligent manner
|
||||||
|
Pre-condition: User is authenticated in the platform
|
||||||
|
Actors: City data publisher
|
||||||
|
Rationale: Data Consumers can register in the platform and request approval to consume city data via GUI
|
||||||
|
or APIs. They provide valid registration details (to be defined) and wait for platform to confirm their
|
||||||
|
registration.
|
||||||
|
Subordinated Use Cases: “Commercialise Data Services (UC8)”
|
||||||
|
Refines into requirements: FREQ 6 to FREQ.26.
|
||||||
|
|
||||||
|
|
||||||
|
Specialised Use Cases Basic Interactions and Responses
|
||||||
|
1. Users / Machines select data service to be utilised
|
||||||
|
2. Users / Machines are redirected to authentication mechanism in
|
||||||
|
UC2.1. User utilises data case of registration is needed for the particular service
|
||||||
|
services o If authentication is successful, users are provided with
|
||||||
|
requested data streams
|
||||||
|
3. Users are provided with requested service either via API or GUI
|
||||||
|
|
||||||
|
|
||||||
|
2.7.4 Functional Requirements
|
||||||
|
|
||||||
|
Req. ID UC. ID Description Priority Domain
|
||||||
|
Provide stable and well-defined interfaces to ensure interoperability
|
||||||
|
Societal Needs,
|
||||||
|
FREQ.84 UC12 between the platform, services and the applications provided by Should Platform
|
||||||
|
services providers
|
||||||
|
Ensure the interfaces of the architecture are open to reduce entry Societal Needs,
|
||||||
|
FREQ.85 UC12 Should
|
||||||
|
barriers and integration issues Platform
|
||||||
|
Provide multi-purposed and network intelligent interfaces to Societal Needs,
|
||||||
|
FREQ.86 UC12 Must
|
||||||
|
providers and consumers of services Platform
|
||||||
|
Provide service providers mechanisms to define the terms and Societal Needs,
|
||||||
|
FREQ.87 UC12 Must
|
||||||
|
conditions of platform services deployment Platform
|
||||||
|
Business Needs,
|
||||||
|
FREQ.88 UC13 Provide statistical information of user’s feedback on service usage Must Platform
|
||||||
|
Allow users to use services to manipulate city data (e.g. Create Societal Needs,
|
||||||
|
FREQ.89 UC10 Must
|
||||||
|
mash ups, integrate) Platform
|
||||||
|
Allow users to provide feedback on usability, and quality of data Societal Needs,
|
||||||
|
FREQ.90 UC14 Must
|
||||||
|
and services provided by the platform Platform
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 34
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
3. Non-functional Requirements
|
||||||
|
3.1 Run-time Quality Requirements
|
||||||
|
3.1.1 Scalability Requirements
|
||||||
|
|
||||||
|
Rationale: The ability of the system to execute its task within its expected performance profile and
|
||||||
|
to handle on-demand increased processing volumes of data and service requests
|
||||||
|
Drivers: Provide ready access to all data that underpins decision making processes in smart cities,
|
||||||
|
and accommodate users and data usage patterns
|
||||||
|
Refines into requirements: NFREQ.1, NFREQ.2, NFREQ.3, NFREQ.4
|
||||||
|
Relevance: Urban platforms have ambitious performance requirements. Such platforms must cope
|
||||||
|
with user’s demand for data and services, capture real-time data that will be catalysed by a myriad
|
||||||
|
of sensors. The demand for urban platform is very likely to significantly increase over time. It is
|
||||||
|
very difficult to have clear performance characteristics due to the ubiquity, heterogeneity high
|
||||||
|
connectivity of devices and end users.
|
||||||
|
|
||||||
|
SCALABILITY MEASURES
|
||||||
|
Actions Capture the performance requirements
|
||||||
|
Create service level agreements
|
||||||
|
Predict scalability using software simulation
|
||||||
|
Analyse the performance of the platform overtime
|
||||||
|
Conduct practical testing
|
||||||
|
Strategy Prioritize service and data requests
|
||||||
|
Distribute processing over time
|
||||||
|
Scale up or scale out as necessary
|
||||||
|
Reuse resources and results Partition and parallelize
|
||||||
|
Constantly monitor Quality of Service at runtime
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
3.1.2 Availability and Reliability Requirements
|
||||||
|
|
||||||
|
Rationale: The ability of the system to be fully or partly operational as and when required and to
|
||||||
|
effectively handle failures that could affect system availability
|
||||||
|
Drivers: Build a reliable foundation for “on demand” exploitation of data
|
||||||
|
Refines into requirements: NFREQ.5, NFREQ.6, NFREQ.7, NFREQ.8
|
||||||
|
Relevance: Any system that has complex or extended availability requirements, complex recovery
|
||||||
|
processes, or a high profile (e.g., is visible to the public)
|
||||||
|
|
||||||
|
AVAILABILITY AND RELIABILITY MEASURES
|
||||||
|
Actions Capture the availability requirements Produce the availability schedule
|
||||||
|
Estimate platform availability Estimate functional availability Assess against the
|
||||||
|
requirements Rework the architecture
|
||||||
|
Strategy Adopt fault-tolerant hardware
|
||||||
|
Use reliable infrastructure database
|
||||||
|
Log transactions
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 35
|
||||||
|
|
||||||
|
|
||||||
|
Develop adaptive software to cope and recover from faults
|
||||||
|
Design and test for failure
|
||||||
|
Deploy load balancing
|
||||||
|
Identify suitable backup and disaster recovery solution
|
||||||
|
|
||||||
|
|
||||||
|
3.1.3 Trust Requirements
|
||||||
|
|
||||||
|
Rationale: A quality related to the user’s belief in the reliability, integrity and ability of the functional
|
||||||
|
behaviour of the platform
|
||||||
|
Drivers: Gain understanding of what influences user’s experience while interacting with services
|
||||||
|
provided
|
||||||
|
Requirements: NFREQ.16, NFREQ.17
|
||||||
|
Relevance: Relevant to the systems that share and collect information that may raise public
|
||||||
|
concern. In some cases, trust has to do with the reliability of data and their providers, whereas in
|
||||||
|
other cases trust can be associated with the security and privacy of the technology that was
|
||||||
|
deployed. Trust affects the reputation of the platform besides its dissemination and maturity on the
|
||||||
|
market.
|
||||||
|
|
||||||
|
TRUST MEASURES
|
||||||
|
Capture trust requirements
|
||||||
|
Perform risk analysis so measures can be implemented
|
||||||
|
Actions Explore the vulnerability aspects of city data
|
||||||
|
Check whether extensibility requirements impact on trust
|
||||||
|
Define a trust model
|
||||||
|
Adopt trust model
|
||||||
|
Deploy monitoring capabilities and assess its impact on scalability
|
||||||
|
Manage the data in a way that ensures its compliance with data
|
||||||
|
Strategy protection regulations
|
||||||
|
Implement tampering and data misuse detection
|
||||||
|
Make use of Cryptography when necessary
|
||||||
|
Allow Federation of trust between platforms
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
3.1.4 Security Requirements
|
||||||
|
|
||||||
|
Rationale: Ability of the system to enforce the intended confidentiality, trust, integrity and service
|
||||||
|
and data access policies, and to detect and recover from failure in these security mechanisms.
|
||||||
|
Drivers: Manage the data and services in a way that ensures its integrity, and compliance with
|
||||||
|
data protection regulations
|
||||||
|
Relevance: Relevant to the systems that share and collect information that may raise public
|
||||||
|
concern. Urban platforms may become a valuable target for attackers which can potentially leave
|
||||||
|
huge swathes of information exposed. It could potentially undermine trust in the government and
|
||||||
|
damage its reputation.
|
||||||
|
Refines into requirements: NFREQ.9 to NFREQ.15
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 36
|
||||||
|
|
||||||
|
|
||||||
|
SECURITY MEASURES
|
||||||
|
Elicit the security requirements
|
||||||
|
Cross-check security requirements’ impact on services offered by different
|
||||||
|
providers
|
||||||
|
Verify security impact on service composition
|
||||||
|
Conduct risk analysis and impacts of security breach
|
||||||
|
Use scalable and efficient user authentication components
|
||||||
|
Use authentication and authorization components to secure interfacing with
|
||||||
|
Actions external services
|
||||||
|
Address aspects of data collection, storage and distribution
|
||||||
|
Address aspects of service and communication security among devices
|
||||||
|
Identify security requirements of the physical infrastructure
|
||||||
|
Balance and prioritize scalability (performance) and security requirements
|
||||||
|
Evaluate trade-offs between privacy considerations and preventing abuse. (While
|
||||||
|
anonymous access guarantees privacy of users, traceability of users due to abuse
|
||||||
|
of the service is not possible.)
|
||||||
|
Toughen user’s functional components
|
||||||
|
Authenticate subjects
|
||||||
|
Define and enforce access policies
|
||||||
|
Secure communication infrastructures
|
||||||
|
Secure interfaces with external systems and services
|
||||||
|
Strategy
|
||||||
|
Secure databases
|
||||||
|
Check data integrity for critical services
|
||||||
|
User digital certificates and encryption where necessary
|
||||||
|
Secure monetary transactions
|
||||||
|
Secure user’s personal information
|
||||||
|
|
||||||
|
|
||||||
|
3.1.5 Privacy Requirements
|
||||||
|
|
||||||
|
Rationale: Ability of the system to ensure that the collection and transmission of personal data is
|
||||||
|
minimized and handled in accordance with user’s expectation and regulations.
|
||||||
|
Drivers: Protect the vulnerability aspects volunteered citizen’s data
|
||||||
|
Requirements: NFREQ.18, NFREQ.19, NFREQ.20, NFREQ.21, NFREQ.22
|
||||||
|
Relevance: Ensuring users privacy is protected positively influences user’s experience,
|
||||||
|
acceptance and continuous use of the platform. Besides other factors, the reputation of the
|
||||||
|
platform depends on how well user’s information is secure and preserved.
|
||||||
|
|
||||||
|
PRIVACY MEASURES
|
||||||
|
Capture trust requirements
|
||||||
|
Perform risk analysis so measures can be implemented
|
||||||
|
Actions Explore the vulnerability aspects of city data
|
||||||
|
Check whether extensibility requirements impact on trust
|
||||||
|
Define a trust model
|
||||||
|
Allow users to interact with the platform anonymously in given
|
||||||
|
circumstances
|
||||||
|
Manage users identification securely
|
||||||
|
Strategy Anonymize data whenever necessary to comply with data regulations
|
||||||
|
Cryptograph personal identifiers during data transmission when that is
|
||||||
|
necessary
|
||||||
|
Avoid unauthorized access to implicit information (e.g. location)
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 37
|
||||||
|
|
||||||
|
|
||||||
|
Verify the impact of security, trust and scalability requirements trade-offs
|
||||||
|
on privacy
|
||||||
|
Allow the user to control how personal information is used
|
||||||
|
Empower user to control the data disclosure mechanism
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
3.2 Non Run-time Quality Requirements
|
||||||
|
3.2.1 Evolvability Requirements
|
||||||
|
|
||||||
|
Rationale: The ability of the platform to withstand and easily adapt when new requirements and
|
||||||
|
changes is introduced.
|
||||||
|
Drivers: Ensure the platform is able to accommodate additional functionality and emerging
|
||||||
|
technologies at later stage at a fair and transparent cost
|
||||||
|
Refines into requirements: NFREQ.23
|
||||||
|
Relevance: Important for longer- lived and more widely used systems. Urban platforms are
|
||||||
|
expected to be highly evolvable in order to accommodate future emerging technologies and avoid
|
||||||
|
interoperability issues.
|
||||||
|
|
||||||
|
EVOLVABILITY MEASURES
|
||||||
|
Actions Characterize and assess the evolution needs
|
||||||
|
Consider the evolution trade-offs
|
||||||
|
Balance and negotiate potential conflicting requirements emerging from
|
||||||
|
the evolution capability.
|
||||||
|
Strategy Adopt standards and open interfaces
|
||||||
|
Design loose-coupled components
|
||||||
|
Preserve the platform resilience
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
3.2.2 Extensibility Requirements
|
||||||
|
|
||||||
|
Rationale: The flexibility of the system to allow services and functionality to be extended and
|
||||||
|
augmented by service providers in order to increase value of services to both platform providers
|
||||||
|
and end-users. The extension of the platform services is determined by the Platform Openness
|
||||||
|
strategy.
|
||||||
|
Drivers: Stakeholders can extend the services provided by the urban platform, so that
|
||||||
|
partnerships can be built to deliver holistic and interoperable solutions. Identify integrated
|
||||||
|
approaches to design and service delivery which ensures that services fit together and that
|
||||||
|
synergies can be exploited.
|
||||||
|
Refines into requirements: NFREQ.24, NFREQ.25
|
||||||
|
Relevance: Important for longer- lived and more widely used systems. Urban platforms are
|
||||||
|
expected to be highly evolvable in order to accommodate future emerging technologies and avoid
|
||||||
|
interoperability issues.
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 38
|
||||||
|
|
||||||
|
|
||||||
|
EXTENSIBILITY
|
||||||
|
Actions Characterize and assess the extensibility needs
|
||||||
|
Trace the impacts and cost of extensions
|
||||||
|
Negotiate potential conflicting requirements emerging from adding extensions
|
||||||
|
in the platform
|
||||||
|
Strategy Develop a modular architecture with standard interfaces that reduces entry
|
||||||
|
barriers due to increased transparency and integration
|
||||||
|
Share technical information about interfaces will help service providers in
|
||||||
|
targeting opportunities around the platform
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
3.3 List of Non-Functional Requirements
|
||||||
|
|
||||||
|
ID # Description Concern Priority Domain
|
||||||
|
|
||||||
|
Platform,
|
||||||
|
NFREQ.1 Support different service level agreements (SLA) Scalability Should
|
||||||
|
Infrastructure
|
||||||
|
Platform,
|
||||||
|
NFREQ.2 Process services and events on a set of distributed nodes Scalability Should
|
||||||
|
Infrastructure
|
||||||
|
Platform,
|
||||||
|
NFREQ.3 Continuously monitor Quality of Service at runtime Scalability Should
|
||||||
|
Infrastructure
|
||||||
|
Platform,
|
||||||
|
NFREQ.4 Balance its load at runtime Scalability Should
|
||||||
|
Infrastructure
|
||||||
|
Platform,
|
||||||
|
NFREQ.5 Provide high availability Availability Should
|
||||||
|
Infrastructure
|
||||||
|
Platform,
|
||||||
|
NFREQ.6 Guarantee infrastructure availability Availability Should
|
||||||
|
Infrastructure
|
||||||
|
Platform,
|
||||||
|
NFREQ.7 Ensure network availability Availability Should
|
||||||
|
Infrastructure
|
||||||
|
Platform,
|
||||||
|
NFREQ.8 Be able to perform self-healing Availability Should
|
||||||
|
Infrastructure
|
||||||
|
City Data,
|
||||||
|
NFREQ.9 Expose data and services to authorized users Security Must
|
||||||
|
Platform
|
||||||
|
City Data,
|
||||||
|
NFREQ.10 Ensure services are always accessible to entitled users Security Must
|
||||||
|
Platform
|
||||||
|
|
||||||
|
NFREQ.11 Ensure Data Freshness Security Must Platform
|
||||||
|
|
||||||
|
NFREQ.12 Support access control mechanisms Security Must Platform
|
||||||
|
|
||||||
|
Platform,
|
||||||
|
NFREQ.13 Have security mechanisms to protect data transmission Security Should
|
||||||
|
Infrastructure
|
||||||
|
Platform,
|
||||||
|
NFREQ.14 Make it difficult to spy on communicated messages Security Should
|
||||||
|
Infrastructure
|
||||||
|
Platform,
|
||||||
|
NFREQ.15 Be able to perform to detect threats at runtime Security Should
|
||||||
|
Infrastructure
|
||||||
|
Provide trusted and secure communication and information Platform,
|
||||||
|
NFREQ.16 Trust Should
|
||||||
|
management Infrastructure
|
||||||
|
|
||||||
|
NFREQ.17 The platform infrastructure and services shall be trustable Trust Should Infrastructure
|
||||||
|
|
||||||
|
Societal Needs,
|
||||||
|
NFREQ.18 Allow users to use free services anonymously Privacy Should
|
||||||
|
Platform
|
||||||
|
Societal Needs,
|
||||||
|
NFREQ.19 Allow people to use free services anonymously Privacy Should
|
||||||
|
Platform
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 39
|
||||||
|
|
||||||
|
|
||||||
|
Allow users to control which data they are willing to provide Societal Needs,
|
||||||
|
NFREQ.20 Privacy Should
|
||||||
|
and how their data should be used Platform
|
||||||
|
|
||||||
|
NFREQ.21 Keep users access-control rights/ policies secured. Privacy Should Platform
|
||||||
|
|
||||||
|
Provide privacy protection for users interacting with the Societal Needs,
|
||||||
|
NFREQ.22 Privacy Should
|
||||||
|
platform Platform
|
||||||
|
Platform,
|
||||||
|
NFREQ.23 Provide communication confidentiality Privacy Should
|
||||||
|
Infrastructure
|
||||||
|
Societal Needs,
|
||||||
|
NFREQ.24 Be extensible for future technologies. Evolvability Must City Data, Platform,
|
||||||
|
Infrastructure
|
||||||
|
Platform,
|
||||||
|
NFREQ.26 Provide standard interfaces for service providers Extensibility Should
|
||||||
|
Business Needs
|
||||||
|
|
||||||
|
NFREQ.26 Be able to provide services in an interoperable manner Extensibility Should Platform
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
4. Other Requirements
|
||||||
|
4.1 Minimal Descriptive Metadata Required from Data Provider
|
||||||
|
|
||||||
|
Minimal Descriptive Metadata Required from Data Provider
|
||||||
|
|
||||||
|
Attribute Required Definition Notes Examples
|
||||||
|
|
||||||
|
Database Name Y A name given to the resource
|
||||||
|
|
||||||
|
Author Name of a person or body associated with
|
||||||
|
Y
|
||||||
|
the creation of the resource
|
||||||
|
|
||||||
|
Maintainer Name of the entity responsible for making
|
||||||
|
Y
|
||||||
|
the resource available
|
||||||
|
|
||||||
|
Date Created Y Date the dataset was created
|
||||||
|
|
||||||
|
|
||||||
|
Date Modified Y Date the dataset was modified
|
||||||
|
|
||||||
|
|
||||||
|
Last Revision Y Date the dataset was last revised
|
||||||
|
|
||||||
|
|
||||||
|
Update Frequency Y Frequency of data maintenance
|
||||||
|
|
||||||
|
|
||||||
|
Mode of Release Y Open/Proprietary
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 40
|
||||||
|
|
||||||
|
|
||||||
|
4.2 Urban Platform Supported Data Formats
|
||||||
|
|
||||||
|
|
||||||
|
MIME type Description Extensions Level
|
||||||
|
|
||||||
|
application/json JavaScript Object Notation json supported
|
||||||
|
|
||||||
|
application/xml eXtensible markup language file xml supported
|
||||||
|
|
||||||
|
text/csv Comma separated values file csv supported
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
5. Conclusion & Forward Plans
|
||||||
|
This document represents the first set of requirements specification for urban platform. Future
|
||||||
|
activities will collaboratively assess, resolve requirements conflicts, prioritize, and validate the
|
||||||
|
requirements of the urban platform. Ultimately, this document will become a complete final
|
||||||
|
requirements specification document to guide and speed up the development open platform for
|
||||||
|
cities. Table below shows the milestones, deliverables and engagement activities completed and
|
||||||
|
yet to be completed by the Demand Side Engagement Stream.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Milestones, deliverables and engagement activity Forecast date Status
|
||||||
|
Stakeholders invitation Late Completed
|
||||||
|
September/2015
|
||||||
|
Online Workshop 1: Project Scope and Outcomes 20/11/2015 Completed
|
||||||
|
Online meeting held with city members to communicate goals,
|
||||||
|
expected outcomes, time commitment and required actions.
|
||||||
|
Start of Collaborative Requirements Engineering Process 20/11/2015 Completed
|
||||||
|
Participants reviewed the first draft of urban platform requirements,
|
||||||
|
provided comments, and suggested new requirements and changes.
|
||||||
|
Online Workshop 2: Review and Refine Requirements 08/12/2015 Completed
|
||||||
|
Participants had a conference call to review the requirements
|
||||||
|
specification document and provide their comments.
|
||||||
|
Deliverable: Requirements Specification Document v2.1 shared 05/01/2016 Completed
|
||||||
|
across the Working Streams for consultation
|
||||||
|
Online Workshop 3: Review Requirements Specification 12/01/2016 Completed
|
||||||
|
Document and discussion of Letter of Intent
|
||||||
|
Participants had a conference call to review the requirements
|
||||||
|
specification document and provide their comments, and discussed
|
||||||
|
the Letter of Intent to be signed by Mayor/Equiv of EU cities to
|
||||||
|
commit to application of common U.P. approach.
|
||||||
|
Urban Platforms Workshop in Brussels 19/01/2016 Completed
|
||||||
|
Participants provided feedback on the requirements specification
|
||||||
|
document and recommended changes in the document
|
||||||
|
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 41
|
||||||
|
|
||||||
|
|
||||||
|
Deliverable: Updated Requirements Specification Document v2.2 29/01/2016 Completed
|
||||||
|
shared with Industry and Standardisation Working Streams
|
||||||
|
Deliverable: Online release of the Requirements Specification Early
|
||||||
|
Document and open calls for wider consultation on the Requirements February/2016
|
||||||
|
|
||||||
|
Online Workshop 4: Engagement with Industry Side Early
|
||||||
|
Capture industry feedback on the Requirements Specification February/2016
|
||||||
|
Document to assess its suitability to drive the development of the first
|
||||||
|
draft reference architecture.
|
||||||
|
Online Workshop 5: Review Requirements Specification Mid
|
||||||
|
Document v2.2 and discuss requirement prioritization and February/2016
|
||||||
|
balancing
|
||||||
|
Collectively determine which candidate requirements of urban
|
||||||
|
platforms should be prioritized as high importance to all the cities
|
||||||
|
(use of Value Oriented Prioritization Method). Requirements are also
|
||||||
|
prioritized to minimize risk during development of urban platforms so
|
||||||
|
that the most important requirements are made explicit and
|
||||||
|
considered in the reference architecture.
|
||||||
|
Capture of case studies from cities intended to support requirements Mid March/2016
|
||||||
|
validation (City of Porto), and learning and confidence building
|
||||||
|
amongst cities.
|
||||||
File diff suppressed because it is too large
Load Diff
+618
-19
@@ -3,6 +3,7 @@ package agent
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -32,6 +33,29 @@ type Orchestrator struct {
|
|||||||
enableCapabilityGap bool
|
enableCapabilityGap bool
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
skillsMu sync.RWMutex
|
skillsMu sync.RWMutex
|
||||||
|
pendingFilesMu sync.Mutex
|
||||||
|
pendingFiles map[string][]pendingFileRef
|
||||||
|
}
|
||||||
|
|
||||||
|
type pendingFileRef struct {
|
||||||
|
ID string
|
||||||
|
Name string
|
||||||
|
MimeType string
|
||||||
|
}
|
||||||
|
|
||||||
|
type capabilityRoutingResult struct {
|
||||||
|
NeedSkills bool
|
||||||
|
SelectedToolNames []string
|
||||||
|
SelectedSkills []knowledge.Skill
|
||||||
|
Reason string
|
||||||
|
UsedFallback bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type filePromptContext struct {
|
||||||
|
Summary string
|
||||||
|
FatalReason string
|
||||||
|
FileIDs []string
|
||||||
|
Uploaded []pendingFileRef
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewOrchestrator 创建一个新的编排器对象,初始化关键路径和超时控制等。
|
// NewOrchestrator 创建一个新的编排器对象,初始化关键路径和超时控制等。
|
||||||
@@ -76,6 +100,7 @@ func NewOrchestrator(
|
|||||||
reactMaxStep: reactMaxStep,
|
reactMaxStep: reactMaxStep,
|
||||||
enableCapabilityGap: enableCapabilityGap,
|
enableCapabilityGap: enableCapabilityGap,
|
||||||
log: log,
|
log: log,
|
||||||
|
pendingFiles: make(map[string][]pendingFileRef),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,12 +110,20 @@ func NewOrchestrator(
|
|||||||
// - 是否需要调用工具(action + action_input)
|
// - 是否需要调用工具(action + action_input)
|
||||||
// 循环持续进行,直到 LLM 返回 is_final_answer=true。
|
// 循环持续进行,直到 LLM 返回 is_final_answer=true。
|
||||||
func (o *Orchestrator) HandleMessage(ctx context.Context, chatID, userID, text string) (string, error) {
|
func (o *Orchestrator) HandleMessage(ctx context.Context, chatID, userID, text string) (string, error) {
|
||||||
|
return o.handleMessageInternal(ctx, chatID, userID, text, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Orchestrator) HandleMessageWithFiles(ctx context.Context, chatID, userID, text string, files []llm.InputFile) (string, error) {
|
||||||
|
return o.handleMessageInternal(ctx, chatID, userID, text, files)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Orchestrator) handleMessageInternal(ctx context.Context, chatID, userID, text string, files []llm.InputFile) (string, error) {
|
||||||
// 为链路追踪设置唯一的 TraceID
|
// 为链路追踪设置唯一的 TraceID
|
||||||
traceID := logger.NewTraceID()
|
traceID := logger.NewTraceID()
|
||||||
ctx = logger.WithTraceID(ctx, traceID)
|
ctx = logger.WithTraceID(ctx, traceID)
|
||||||
traceLogPrefix := "trace_id=" + traceID
|
traceLogPrefix := "trace_id=" + traceID
|
||||||
if o.log != nil {
|
if o.log != nil {
|
||||||
o.log.Infof("%s handle message chat_id=%s user_id=%s text_len=%d", traceLogPrefix, chatID, userID, len(text))
|
o.log.Infof("%s handle message chat_id=%s user_id=%s text_len=%d files=%d", traceLogPrefix, chatID, userID, len(text), len(files))
|
||||||
o.log.Debugf("%s handle message text=%q", traceLogPrefix, text)
|
o.log.Debugf("%s handle message text=%q", traceLogPrefix, text)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,6 +144,38 @@ func (o *Orchestrator) HandleMessage(ctx context.Context, chatID, userID, text s
|
|||||||
return report, nil
|
return report, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trimmedText := strings.TrimSpace(text)
|
||||||
|
isFileOnly := len(files) > 0 && trimmedText == ""
|
||||||
|
|
||||||
|
if isFileOnly {
|
||||||
|
if err := o.store.SaveMessage(chatID, userID, "user", "[FILE_UPLOAD]"); err != nil {
|
||||||
|
if o.log != nil {
|
||||||
|
o.log.Errorf("%s save file-only user marker failed chat_id=%s err=%v", traceLogPrefix, chatID, err)
|
||||||
|
}
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
uploadCtx := o.prepareFilePromptContext(ctx, files, nil)
|
||||||
|
if strings.TrimSpace(uploadCtx.FatalReason) != "" {
|
||||||
|
finalText := "文件上传失败,无法建立文档上下文。" + "\n" + uploadCtx.FatalReason
|
||||||
|
if err := o.store.SaveMessage(chatID, userID, "assistant", finalText); err != nil && o.log != nil {
|
||||||
|
o.log.Warnf("%s save upload failure message failed chat_id=%s err=%v", traceLogPrefix, chatID, err)
|
||||||
|
}
|
||||||
|
return finalText, nil
|
||||||
|
}
|
||||||
|
o.appendPendingFiles(chatID, userID, uploadCtx.toPendingRefs())
|
||||||
|
finalText := o.buildFileUploadAck(uploadCtx)
|
||||||
|
if err := o.store.SaveMessage(chatID, userID, "assistant", finalText); err != nil {
|
||||||
|
if o.log != nil {
|
||||||
|
o.log.Errorf("%s save file upload ack failed chat_id=%s err=%v", traceLogPrefix, chatID, err)
|
||||||
|
}
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if o.log != nil {
|
||||||
|
o.log.Infof("%s file-only message handled chat_id=%s cached_files=%d", traceLogPrefix, chatID, len(uploadCtx.FileIDs))
|
||||||
|
}
|
||||||
|
return finalText, nil
|
||||||
|
}
|
||||||
|
|
||||||
// 保存用户消息到 SQLite 中
|
// 保存用户消息到 SQLite 中
|
||||||
if err := o.store.SaveMessage(chatID, userID, "user", text); err != nil {
|
if err := o.store.SaveMessage(chatID, userID, "user", text); err != nil {
|
||||||
if o.log != nil {
|
if o.log != nil {
|
||||||
@@ -133,13 +198,30 @@ func (o *Orchestrator) HandleMessage(ctx context.Context, chatID, userID, text s
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 进入统一 ReAct 循环
|
// 进入统一 ReAct 循环
|
||||||
response, err := o.runUnifiedReAct(ctx, chatID, userID, compressed, text)
|
pendingRefs := o.getPendingFiles(chatID, userID)
|
||||||
|
fileCtx := o.prepareFilePromptContext(ctx, files, pendingRefs)
|
||||||
|
if strings.TrimSpace(fileCtx.FatalReason) != "" {
|
||||||
|
finalText := "文件上传失败,无法继续进行文档解析。" + "\n" + fileCtx.FatalReason
|
||||||
|
if err := o.store.SaveMessage(chatID, userID, "assistant", finalText); err != nil && o.log != nil {
|
||||||
|
o.log.Warnf("%s save assistant failure message failed chat_id=%s err=%v", traceLogPrefix, chatID, err)
|
||||||
|
}
|
||||||
|
if o.log != nil {
|
||||||
|
o.log.Warnf("%s stop before react due to file upload failure reason=%s", traceLogPrefix, fileCtx.FatalReason)
|
||||||
|
}
|
||||||
|
return finalText, nil
|
||||||
|
}
|
||||||
|
routeInput := composeRouteInput(text, fileCtx.Summary)
|
||||||
|
route := o.routeCapabilities(ctx, routeInput)
|
||||||
|
response, err := o.runUnifiedReAct(ctx, chatID, userID, compressed, text, fileCtx, routeInput, route)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if o.log != nil {
|
if o.log != nil {
|
||||||
o.log.Errorf("%s message generation failed chat_id=%s err=%v", traceLogPrefix, chatID, err)
|
o.log.Errorf("%s message generation failed chat_id=%s err=%v", traceLogPrefix, chatID, err)
|
||||||
}
|
}
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
if len(pendingRefs) > 0 {
|
||||||
|
o.clearPendingFiles(chatID, userID)
|
||||||
|
}
|
||||||
|
|
||||||
// 最终将机器人的回复也加入记忆缓存
|
// 最终将机器人的回复也加入记忆缓存
|
||||||
if err := o.store.SaveMessage(chatID, userID, "assistant", response); err != nil {
|
if err := o.store.SaveMessage(chatID, userID, "assistant", response); err != nil {
|
||||||
@@ -156,21 +238,29 @@ func (o *Orchestrator) HandleMessage(ctx context.Context, chatID, userID, text s
|
|||||||
}
|
}
|
||||||
|
|
||||||
// buildUnifiedSystemPrompt 构建统一 ReAct 循环的 system prompt。
|
// buildUnifiedSystemPrompt 构建统一 ReAct 循环的 system prompt。
|
||||||
// 包含人格设定、所有可用技能(含完整内容)、所有可用工具、以及 JSON 输出格式约束。
|
// 工具始终可用;技能仅按当前问题挑选相关项作为增强上下文。
|
||||||
func (o *Orchestrator) buildUnifiedSystemPrompt() string {
|
func (o *Orchestrator) buildUnifiedSystemPrompt(userInput string, route capabilityRoutingResult) string {
|
||||||
skillMetaDoc := o.formatSkillSummariesForPrompt()
|
skillMetaDoc := o.formatSkillSummariesForPrompt()
|
||||||
allSkillsDoc := o.formatAllSkillsContent()
|
relevantSkillsDoc := o.formatSelectedSkillsForPrompt(userInput, route.SelectedSkills)
|
||||||
toolDoc := o.formatToolDoc()
|
toolDoc := o.formatToolDoc()
|
||||||
|
runtimeDoc := formatRuntimeContextForPrompt()
|
||||||
|
routeDoc := formatRouteForPrompt(route)
|
||||||
|
|
||||||
return strings.Join([]string{
|
return strings.Join([]string{
|
||||||
"你是一个个人自动化助手,必须遵循如下人格设定并保持一致:",
|
"你是一个个人自动化助手,必须遵循如下人格设定并保持一致:",
|
||||||
o.soul,
|
o.soul,
|
||||||
"",
|
"",
|
||||||
|
"===== 运行环境 =====",
|
||||||
|
runtimeDoc,
|
||||||
|
"",
|
||||||
"===== 可用技能概览 =====",
|
"===== 可用技能概览 =====",
|
||||||
skillMetaDoc,
|
skillMetaDoc,
|
||||||
"",
|
"",
|
||||||
"===== 技能详细说明 =====",
|
"===== 能力路由结果 =====",
|
||||||
allSkillsDoc,
|
routeDoc,
|
||||||
|
"",
|
||||||
|
"===== 本轮相关技能(按用户问题筛选) =====",
|
||||||
|
relevantSkillsDoc,
|
||||||
"",
|
"",
|
||||||
"===== 可用工具 =====",
|
"===== 可用工具 =====",
|
||||||
toolDoc,
|
toolDoc,
|
||||||
@@ -190,25 +280,32 @@ func (o *Orchestrator) buildUnifiedSystemPrompt() string {
|
|||||||
"决策规则:",
|
"决策规则:",
|
||||||
"1) 如果你可以直接回答用户问题(不需要任何工具):",
|
"1) 如果你可以直接回答用户问题(不需要任何工具):",
|
||||||
" 设 is_final_answer=true,action=\"none\",final_answer 填写完整回复。",
|
" 设 is_final_answer=true,action=\"none\",final_answer 填写完整回复。",
|
||||||
"2) 如果你需要调用工具获取信息后才能回答:",
|
"2) 优先判断是否可通过原子工具能力完成任务;若可完成,直接进行工具调用链路。",
|
||||||
|
"3) 当纯工具调用无法满足时,再结合已加载的技能详细说明进行决策。",
|
||||||
|
"4) 如果你需要调用工具获取信息后才能回答:",
|
||||||
" 设 is_final_answer=false,action 填工具名,action_input 填工具所需输入,final_answer=null。",
|
" 设 is_final_answer=false,action 填工具名,action_input 填工具所需输入,final_answer=null。",
|
||||||
"3) 不要在 JSON 之外输出任何内容。",
|
"5) 不要在 JSON 之外输出任何内容。",
|
||||||
"4) 根据技能说明中的指引决定何时以及如何使用工具。",
|
"6) 根据技能说明中的指引决定何时以及如何使用工具。",
|
||||||
"5) 每轮工具调用结果会以 Observation 的形式追加到推理记录中,供你下一轮决策参考。",
|
"7) 工具能力是全局可用的,不依赖技能命中;当技能不匹配时,仍可直接选择合适工具。",
|
||||||
|
"8) 若技能中存在与当前运行环境不匹配的章节(如 Windows 专章),应降低优先级,除非用户明确要求该环境。",
|
||||||
|
"9) 每轮工具调用结果会以 Observation 的形式追加到推理记录中,供你下一轮决策参考。",
|
||||||
}, "\n")
|
}, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
// runUnifiedReAct 执行统一的 ReAct 循环。
|
// runUnifiedReAct 执行统一的 ReAct 循环。
|
||||||
// LLM 每次都看到完整的技能集+工具集,自行决定是否调用工具或直接回答。
|
// LLM 每次都看到完整的技能集+工具集,自行决定是否调用工具或直接回答。
|
||||||
// 循环持续到 is_final_answer=true 或达到安全上限。
|
// 循环持续到 is_final_answer=true 或达到安全上限。
|
||||||
func (o *Orchestrator) runUnifiedReAct(ctx context.Context, chatID, userID, compressedContext, userInput string) (string, error) {
|
func (o *Orchestrator) runUnifiedReAct(ctx context.Context, chatID, userID, compressedContext, userInput string, fileCtx filePromptContext, routeInput string, route capabilityRoutingResult) (string, error) {
|
||||||
traceID := logger.TraceIDFromContext(ctx)
|
traceID := logger.TraceIDFromContext(ctx)
|
||||||
traceLogPrefix := "trace_id=" + traceID
|
traceLogPrefix := "trace_id=" + traceID
|
||||||
|
|
||||||
systemPrompt := o.buildUnifiedSystemPrompt()
|
if strings.TrimSpace(routeInput) == "" {
|
||||||
|
routeInput = composeRouteInput(userInput, fileCtx.Summary)
|
||||||
|
}
|
||||||
|
systemPrompt := o.buildUnifiedSystemPrompt(routeInput, route)
|
||||||
|
|
||||||
if o.log != nil {
|
if o.log != nil {
|
||||||
o.log.Infof("%s unified react start", traceLogPrefix)
|
o.log.Infof("%s unified react start route_need_skills=%v route_tools=%v route_skills=%d fallback=%v", traceLogPrefix, route.NeedSkills, route.SelectedToolNames, len(route.SelectedSkills), route.UsedFallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 安全上限:防止无限循环(当前暂不使用 reactMaxStep 配置约束,使用固定硬上限)
|
// 安全上限:防止无限循环(当前暂不使用 reactMaxStep 配置约束,使用固定硬上限)
|
||||||
@@ -229,13 +326,16 @@ func (o *Orchestrator) runUnifiedReAct(ctx context.Context, chatID, userID, comp
|
|||||||
"用户问题:",
|
"用户问题:",
|
||||||
userInput,
|
userInput,
|
||||||
"",
|
"",
|
||||||
|
"文件上下文:",
|
||||||
|
defaultIfEmpty(fileCtx.Summary, "(none)"),
|
||||||
|
"",
|
||||||
"当前推理记录(按时间顺序):",
|
"当前推理记录(按时间顺序):",
|
||||||
scratchpad,
|
scratchpad,
|
||||||
"",
|
"",
|
||||||
"请输出你的 JSON 决策。",
|
"请输出你的 JSON 决策。",
|
||||||
}, "\n")
|
}, "\n")
|
||||||
|
|
||||||
raw, err := o.llm.Generate(ctx, systemPrompt, prompt)
|
raw, err := o.generateWithOptionalFiles(ctx, systemPrompt, prompt, fileCtx.FileIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -335,15 +435,514 @@ func (o *Orchestrator) runUnifiedReAct(ctx context.Context, chatID, userID, comp
|
|||||||
return "我尝试了多轮推理与工具调用,但仍未得到稳定结论。请给我更具体的约束或允许我继续尝试。", nil
|
return "我尝试了多轮推理与工具调用,但仍未得到稳定结论。请给我更具体的约束或允许我继续尝试。", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// formatAllSkillsContent 返回所有技能的完整内容,用于注入到 system prompt 中。
|
func composeRouteInput(userInput, fileSummary string) string {
|
||||||
func (o *Orchestrator) formatAllSkillsContent() string {
|
userInput = strings.TrimSpace(userInput)
|
||||||
skills := o.getSkillsSnapshot()
|
fileSummary = strings.TrimSpace(fileSummary)
|
||||||
|
if userInput == "" {
|
||||||
|
return fileSummary
|
||||||
|
}
|
||||||
|
if fileSummary == "" {
|
||||||
|
return userInput
|
||||||
|
}
|
||||||
|
return userInput + "\n\n" + fileSummary
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Orchestrator) prepareFilePromptContext(ctx context.Context, files []llm.InputFile, pending []pendingFileRef) filePromptContext {
|
||||||
|
ctxOut := filePromptContext{}
|
||||||
|
if len(pending) > 0 {
|
||||||
|
for _, p := range pending {
|
||||||
|
id := strings.TrimSpace(p.ID)
|
||||||
|
if id == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ctxOut.FileIDs = append(ctxOut.FileIDs, id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(files) == 0 {
|
||||||
|
ctxOut.Summary = buildFileSummary(pending, nil)
|
||||||
|
return ctxOut
|
||||||
|
}
|
||||||
|
uploader, ok := o.llm.(llm.FileUploader)
|
||||||
|
if !ok {
|
||||||
|
return filePromptContext{FatalReason: "检测到文件输入,但当前 LLM 客户端不支持文件上传接口。"}
|
||||||
|
}
|
||||||
|
|
||||||
|
uploaded := make([]pendingFileRef, 0, len(files))
|
||||||
|
for i, f := range files {
|
||||||
|
if strings.TrimSpace(f.FileName) == "" || len(f.Content) == 0 {
|
||||||
|
return filePromptContext{FatalReason: fmt.Sprintf("file[%d] 缺少文件名或内容,无法上传。", i+1)}
|
||||||
|
}
|
||||||
|
fileID, err := uploader.UploadFile(ctx, f, "file-extract")
|
||||||
|
if err != nil {
|
||||||
|
return filePromptContext{FatalReason: fmt.Sprintf("file[%d] name=%s 上传失败: %v", i+1, f.FileName, err)}
|
||||||
|
}
|
||||||
|
ctxOut.FileIDs = append(ctxOut.FileIDs, fileID)
|
||||||
|
uploaded = append(uploaded, pendingFileRef{
|
||||||
|
ID: fileID,
|
||||||
|
Name: strings.TrimSpace(f.FileName),
|
||||||
|
MimeType: defaultIfEmpty(strings.TrimSpace(f.MimeType), "application/octet-stream"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
ctxOut.Uploaded = uploaded
|
||||||
|
ctxOut.Summary = buildFileSummary(pending, uploaded)
|
||||||
|
return ctxOut
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildFileSummary(pending, uploaded []pendingFileRef) string {
|
||||||
|
if len(pending) == 0 && len(uploaded) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
lines := make([]string, 0, len(pending)+len(uploaded)+2)
|
||||||
|
lines = append(lines, "以下文件 file_id 可用于本轮问答:")
|
||||||
|
idx := 1
|
||||||
|
for _, p := range pending {
|
||||||
|
id := strings.TrimSpace(p.ID)
|
||||||
|
if id == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
lines = append(lines, fmt.Sprintf("- cached_file[%d] name=%s mime=%s file_id=%s", idx, defaultIfEmpty(strings.TrimSpace(p.Name), "(unknown)"), defaultIfEmpty(strings.TrimSpace(p.MimeType), "application/octet-stream"), id))
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
for _, p := range uploaded {
|
||||||
|
id := strings.TrimSpace(p.ID)
|
||||||
|
if id == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
lines = append(lines, fmt.Sprintf("- uploaded_file[%d] name=%s mime=%s file_id=%s", idx, defaultIfEmpty(strings.TrimSpace(p.Name), "(unknown)"), defaultIfEmpty(strings.TrimSpace(p.MimeType), "application/octet-stream"), id))
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
if len(lines) == 1 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return strings.Join(lines, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Orchestrator) generateWithOptionalFiles(ctx context.Context, systemPrompt, userPrompt string, fileIDs []string) (string, error) {
|
||||||
|
ids := nonEmptyIDs(fileIDs)
|
||||||
|
if len(ids) == 0 {
|
||||||
|
return o.llm.Generate(ctx, systemPrompt, userPrompt)
|
||||||
|
}
|
||||||
|
client, ok := o.llm.(llm.FileChatClient)
|
||||||
|
if !ok {
|
||||||
|
return o.llm.Generate(ctx, systemPrompt, userPrompt)
|
||||||
|
}
|
||||||
|
return client.GenerateWithFiles(ctx, systemPrompt, userPrompt, ids)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Orchestrator) buildFileUploadAck(ctx filePromptContext) string {
|
||||||
|
if len(ctx.FileIDs) == 0 {
|
||||||
|
return "文件已接收,但未拿到有效 file_id。请重新上传一次。"
|
||||||
|
}
|
||||||
|
lines := []string{
|
||||||
|
fmt.Sprintf("文件上传完成,已缓存 %d 个 file_id。", len(ctx.FileIDs)),
|
||||||
|
"请继续发送你的问题,我会结合这些文件内容和历史对话一起回答。",
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(ctx.Summary) != "" {
|
||||||
|
lines = append(lines, "", ctx.Summary)
|
||||||
|
}
|
||||||
|
return strings.Join(lines, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func nonEmptyIDs(ids []string) []string {
|
||||||
|
if len(ids) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := make([]string, 0, len(ids))
|
||||||
|
seen := map[string]struct{}{}
|
||||||
|
for _, id := range ids {
|
||||||
|
id = strings.TrimSpace(id)
|
||||||
|
if id == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, ok := seen[id]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen[id] = struct{}{}
|
||||||
|
out = append(out, id)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c filePromptContext) toPendingRefs() []pendingFileRef {
|
||||||
|
if len(c.Uploaded) > 0 {
|
||||||
|
copied := make([]pendingFileRef, len(c.Uploaded))
|
||||||
|
copy(copied, c.Uploaded)
|
||||||
|
return sanitizePendingRefs(copied)
|
||||||
|
}
|
||||||
|
ids := nonEmptyIDs(c.FileIDs)
|
||||||
|
out := make([]pendingFileRef, 0, len(ids))
|
||||||
|
for _, id := range ids {
|
||||||
|
out = append(out, pendingFileRef{ID: id})
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Orchestrator) appendPendingFiles(chatID, userID string, refs []pendingFileRef) {
|
||||||
|
refs = sanitizePendingRefs(refs)
|
||||||
|
if len(refs) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
key := pendingFileKey(chatID, userID)
|
||||||
|
o.pendingFilesMu.Lock()
|
||||||
|
defer o.pendingFilesMu.Unlock()
|
||||||
|
merged := append(o.pendingFiles[key], refs...)
|
||||||
|
o.pendingFiles[key] = sanitizePendingRefs(merged)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Orchestrator) getPendingFiles(chatID, userID string) []pendingFileRef {
|
||||||
|
key := pendingFileKey(chatID, userID)
|
||||||
|
o.pendingFilesMu.Lock()
|
||||||
|
defer o.pendingFilesMu.Unlock()
|
||||||
|
snapshot := o.pendingFiles[key]
|
||||||
|
out := make([]pendingFileRef, len(snapshot))
|
||||||
|
copy(out, snapshot)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Orchestrator) clearPendingFiles(chatID, userID string) {
|
||||||
|
key := pendingFileKey(chatID, userID)
|
||||||
|
o.pendingFilesMu.Lock()
|
||||||
|
defer o.pendingFilesMu.Unlock()
|
||||||
|
delete(o.pendingFiles, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func pendingFileKey(chatID, userID string) string {
|
||||||
|
return strings.TrimSpace(chatID) + "::" + strings.TrimSpace(userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sanitizePendingRefs(refs []pendingFileRef) []pendingFileRef {
|
||||||
|
if len(refs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := make([]pendingFileRef, 0, len(refs))
|
||||||
|
seen := map[string]struct{}{}
|
||||||
|
for _, r := range refs {
|
||||||
|
id := strings.TrimSpace(r.ID)
|
||||||
|
if id == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, ok := seen[id]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen[id] = struct{}{}
|
||||||
|
r.ID = id
|
||||||
|
r.Name = strings.TrimSpace(r.Name)
|
||||||
|
r.MimeType = strings.TrimSpace(r.MimeType)
|
||||||
|
out = append(out, r)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultIfEmpty(v, fallback string) string {
|
||||||
|
if strings.TrimSpace(v) == "" {
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// formatRelevantSkillsForPrompt 返回与当前用户问题最相关的技能内容。
|
||||||
|
func (o *Orchestrator) formatSelectedSkillsForPrompt(userInput string, selected []knowledge.Skill) string {
|
||||||
|
skills := selected
|
||||||
if len(skills) == 0 {
|
if len(skills) == 0 {
|
||||||
return "(none)"
|
skills = o.selectRelevantSkills(userInput, 4)
|
||||||
|
}
|
||||||
|
if len(skills) == 0 {
|
||||||
|
return "(none matched, tools are still globally available)"
|
||||||
}
|
}
|
||||||
return formatSkills(skills)
|
return formatSkills(skills)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *Orchestrator) routeCapabilities(ctx context.Context, userInput string) capabilityRoutingResult {
|
||||||
|
fallback := capabilityRoutingResult{
|
||||||
|
NeedSkills: true,
|
||||||
|
SelectedSkills: o.selectRelevantSkills(userInput, 4),
|
||||||
|
Reason: "router fallback: keyword matching",
|
||||||
|
UsedFallback: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
raw, err := o.llm.Generate(ctx, o.buildRouteSystemPrompt(), o.buildRouteUserPrompt(userInput))
|
||||||
|
if err != nil {
|
||||||
|
if o.log != nil {
|
||||||
|
o.log.Warnf("capability router llm call failed err=%v", err)
|
||||||
|
}
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
decision, err := parseCapabilityRoute(raw)
|
||||||
|
if err != nil {
|
||||||
|
if o.log != nil {
|
||||||
|
o.log.Warnf("capability router parse failed err=%v raw=%q", err, raw)
|
||||||
|
}
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
resolvedTools := o.normalizeToolSelection(decision.SelectedTools)
|
||||||
|
resolved := capabilityRoutingResult{
|
||||||
|
NeedSkills: decision.NeedSkills,
|
||||||
|
SelectedToolNames: resolvedTools,
|
||||||
|
Reason: strings.TrimSpace(decision.Reason),
|
||||||
|
}
|
||||||
|
|
||||||
|
if resolved.NeedSkills {
|
||||||
|
skills := o.resolveSkillsByNames(decision.SelectedSkills, 4)
|
||||||
|
if len(skills) == 0 {
|
||||||
|
skills = o.selectRelevantSkills(userInput, 4)
|
||||||
|
resolved.UsedFallback = true
|
||||||
|
}
|
||||||
|
resolved.SelectedSkills = skills
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolved
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Orchestrator) buildRouteSystemPrompt() string {
|
||||||
|
return strings.Join([]string{
|
||||||
|
"你是能力路由器(Router Agent)。",
|
||||||
|
"你的任务是:在不加载技能全文的前提下,仅根据工具摘要和技能摘要,判断本请求是否可以仅靠原子工具能力完成,还是需要加载技能详细说明。",
|
||||||
|
"输出必须且仅能是 JSON:",
|
||||||
|
"{",
|
||||||
|
" \"need_skills\": true 或 false,",
|
||||||
|
" \"selected_tools\": [\"tool_name\", ...],",
|
||||||
|
" \"selected_skills\": [\"skill_name\", ...],",
|
||||||
|
" \"reason\": \"简短路由理由\"",
|
||||||
|
"}",
|
||||||
|
"规则:",
|
||||||
|
"1) 优先原子工具能力。若可通过工具链路完成,need_skills=false。",
|
||||||
|
"2) 只有当工具能力不足以覆盖业务约束时,need_skills=true 并选择少量最相关技能。",
|
||||||
|
"3) selected_skills 仅填写技能名称(来自技能摘要)。",
|
||||||
|
"4) selected_tools 仅填写可用工具名。",
|
||||||
|
"5) 不要输出 JSON 之外内容。",
|
||||||
|
}, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Orchestrator) buildRouteUserPrompt(userInput string) string {
|
||||||
|
return strings.Join([]string{
|
||||||
|
"当前运行环境:",
|
||||||
|
formatRuntimeContextForPrompt(),
|
||||||
|
"",
|
||||||
|
"用户问题:",
|
||||||
|
userInput,
|
||||||
|
"",
|
||||||
|
"可用工具摘要:",
|
||||||
|
o.formatToolDoc(),
|
||||||
|
"",
|
||||||
|
"可用技能摘要:",
|
||||||
|
o.formatSkillSummariesForPrompt(),
|
||||||
|
"",
|
||||||
|
"请给出路由 JSON。",
|
||||||
|
}, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Orchestrator) normalizeToolSelection(in []string) []string {
|
||||||
|
if len(in) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
allowed := map[string]struct{}{}
|
||||||
|
for _, t := range o.tools.List() {
|
||||||
|
allowed[strings.ToLower(strings.TrimSpace(t.Name()))] = struct{}{}
|
||||||
|
}
|
||||||
|
out := make([]string, 0, len(in))
|
||||||
|
set := map[string]struct{}{}
|
||||||
|
for _, name := range in {
|
||||||
|
n := strings.ToLower(strings.TrimSpace(name))
|
||||||
|
if n == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, ok := allowed[n]; !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, exists := set[n]; exists {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
set[n] = struct{}{}
|
||||||
|
out = append(out, n)
|
||||||
|
}
|
||||||
|
sort.Strings(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Orchestrator) resolveSkillsByNames(names []string, maxCount int) []knowledge.Skill {
|
||||||
|
if len(names) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if maxCount <= 0 {
|
||||||
|
maxCount = 4
|
||||||
|
}
|
||||||
|
all := o.getSkillsSnapshot()
|
||||||
|
idx := make(map[string]knowledge.Skill, len(all))
|
||||||
|
for _, sk := range all {
|
||||||
|
key := strings.ToLower(strings.TrimSpace(sk.Name))
|
||||||
|
if key != "" {
|
||||||
|
idx[key] = sk
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out := make([]knowledge.Skill, 0, maxCount)
|
||||||
|
used := map[string]struct{}{}
|
||||||
|
for _, name := range names {
|
||||||
|
key := strings.ToLower(strings.TrimSpace(name))
|
||||||
|
if key == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sk, ok := idx[key]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, exists := used[key]; exists {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
used[key] = struct{}{}
|
||||||
|
out = append(out, sk)
|
||||||
|
if len(out) >= maxCount {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatRouteForPrompt(route capabilityRoutingResult) string {
|
||||||
|
b := strings.Builder{}
|
||||||
|
if route.UsedFallback {
|
||||||
|
b.WriteString("router_status: fallback\n")
|
||||||
|
} else {
|
||||||
|
b.WriteString("router_status: ok\n")
|
||||||
|
}
|
||||||
|
b.WriteString("need_skills: ")
|
||||||
|
b.WriteString(strconv.FormatBool(route.NeedSkills))
|
||||||
|
b.WriteString("\n")
|
||||||
|
b.WriteString("selected_tools: ")
|
||||||
|
if len(route.SelectedToolNames) == 0 {
|
||||||
|
b.WriteString("(none)")
|
||||||
|
} else {
|
||||||
|
b.WriteString(strings.Join(route.SelectedToolNames, ", "))
|
||||||
|
}
|
||||||
|
b.WriteString("\n")
|
||||||
|
b.WriteString("selected_skill_count: ")
|
||||||
|
b.WriteString(strconv.Itoa(len(route.SelectedSkills)))
|
||||||
|
b.WriteString("\n")
|
||||||
|
if strings.TrimSpace(route.Reason) != "" {
|
||||||
|
b.WriteString("reason: ")
|
||||||
|
b.WriteString(strings.TrimSpace(route.Reason))
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(b.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Orchestrator) selectRelevantSkills(userInput string, maxCount int) []knowledge.Skill {
|
||||||
|
if maxCount <= 0 {
|
||||||
|
maxCount = 4
|
||||||
|
}
|
||||||
|
query := strings.TrimSpace(strings.ToLower(userInput))
|
||||||
|
all := o.getSkillsSnapshot()
|
||||||
|
if query == "" || len(all) <= maxCount {
|
||||||
|
return all
|
||||||
|
}
|
||||||
|
|
||||||
|
queryTokens := buildQueryTokens(query)
|
||||||
|
type item struct {
|
||||||
|
skill knowledge.Skill
|
||||||
|
score int
|
||||||
|
}
|
||||||
|
ranked := make([]item, 0, len(all))
|
||||||
|
|
||||||
|
for _, sk := range all {
|
||||||
|
hay := strings.ToLower(sk.Name + "\n" + clipForScoring(sk.Content, 1800))
|
||||||
|
score := 0
|
||||||
|
if strings.Contains(hay, query) {
|
||||||
|
score += 8
|
||||||
|
}
|
||||||
|
for _, tk := range queryTokens {
|
||||||
|
if strings.Contains(hay, tk) {
|
||||||
|
score++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if score == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ranked = append(ranked, item{skill: sk, score: score})
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ranked) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(ranked, func(i, j int) bool {
|
||||||
|
if ranked[i].score == ranked[j].score {
|
||||||
|
return strings.ToLower(strings.TrimSpace(ranked[i].skill.Name)) < strings.ToLower(strings.TrimSpace(ranked[j].skill.Name))
|
||||||
|
}
|
||||||
|
return ranked[i].score > ranked[j].score
|
||||||
|
})
|
||||||
|
|
||||||
|
if len(ranked) > maxCount {
|
||||||
|
ranked = ranked[:maxCount]
|
||||||
|
}
|
||||||
|
out := make([]knowledge.Skill, 0, len(ranked))
|
||||||
|
for _, r := range ranked {
|
||||||
|
out = append(out, r.skill)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildQueryTokens(query string) []string {
|
||||||
|
set := map[string]struct{}{}
|
||||||
|
collectToken := func(t string) {
|
||||||
|
t = strings.TrimSpace(t)
|
||||||
|
if len([]rune(t)) < 2 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
set[t] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, part := range strings.FieldsFunc(query, func(r rune) bool {
|
||||||
|
if r >= 'a' && r <= 'z' {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if r >= '0' && r <= '9' {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if r >= 0x4e00 && r <= 0x9fff {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}) {
|
||||||
|
collectToken(part)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 针对中文无空格输入,补充 2-gram 提升匹配命中率。
|
||||||
|
runes := []rune(query)
|
||||||
|
for i := 0; i+1 < len(runes); i++ {
|
||||||
|
r1 := runes[i]
|
||||||
|
r2 := runes[i+1]
|
||||||
|
if (r1 >= 0x4e00 && r1 <= 0x9fff) && (r2 >= 0x4e00 && r2 <= 0x9fff) {
|
||||||
|
collectToken(string([]rune{r1, r2}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out := make([]string, 0, len(set))
|
||||||
|
for tk := range set {
|
||||||
|
out = append(out, tk)
|
||||||
|
}
|
||||||
|
sort.Strings(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func clipForScoring(s string, maxRunes int) string {
|
||||||
|
if maxRunes <= 0 {
|
||||||
|
maxRunes = 1800
|
||||||
|
}
|
||||||
|
r := []rune(s)
|
||||||
|
if len(r) <= maxRunes {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return string(r[:maxRunes])
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatRuntimeContextForPrompt() string {
|
||||||
|
goos := strings.TrimSpace(strings.ToLower(runtime.GOOS))
|
||||||
|
if goos == "" {
|
||||||
|
goos = "unknown"
|
||||||
|
}
|
||||||
|
return "当前运行系统 GOOS=" + goos + "。请优先使用与该系统一致的策略。仅当用户明确要求时,才采用其他系统(如 Windows)的专用流程。"
|
||||||
|
}
|
||||||
|
|
||||||
// emitCapabilityGap 处理能力缺口信息埋点或者通过 AI 自动创建生成相应缺失技能的逻辑
|
// emitCapabilityGap 处理能力缺口信息埋点或者通过 AI 自动创建生成相应缺失技能的逻辑
|
||||||
func (o *Orchestrator) emitCapabilityGap(chatID, userID, intent, reason string) {
|
func (o *Orchestrator) emitCapabilityGap(chatID, userID, intent, reason string) {
|
||||||
if !o.enableCapabilityGap {
|
if !o.enableCapabilityGap {
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package agent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"laodingbot/internal/knowledge"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBuildQueryTokensIncludesChineseBigrams(t *testing.T) {
|
||||||
|
tokens := buildQueryTokens("请执行命令并查看文件")
|
||||||
|
joined := strings.Join(tokens, ",")
|
||||||
|
if !strings.Contains(joined, "命令") {
|
||||||
|
t.Fatalf("expected token contains 命令, got: %v", tokens)
|
||||||
|
}
|
||||||
|
if !strings.Contains(joined, "文件") {
|
||||||
|
t.Fatalf("expected token contains 文件, got: %v", tokens)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSelectRelevantSkillsPrefersMatchingSkill(t *testing.T) {
|
||||||
|
o := &Orchestrator{
|
||||||
|
skills: []knowledge.Skill{
|
||||||
|
{Name: "文件系统查询专家", Content: "适用于目录、文件、路径、命令执行等场景"},
|
||||||
|
{Name: "天气查询", Content: "用于天气和空气质量查询"},
|
||||||
|
{Name: "日程助手", Content: "用于日程管理"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
selected := o.selectRelevantSkills("帮我执行命令查看某个文件", 2)
|
||||||
|
if len(selected) == 0 {
|
||||||
|
t.Fatal("expected non-empty selected skills")
|
||||||
|
}
|
||||||
|
if selected[0].Name != "文件系统查询专家" {
|
||||||
|
t.Fatalf("expected top skill 文件系统查询专家, got: %s", selected[0].Name)
|
||||||
|
}
|
||||||
|
if len(selected) > 2 {
|
||||||
|
t.Fatalf("expected at most 2 skills, got: %d", len(selected))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFormatRuntimeContextForPromptIncludesGOOS(t *testing.T) {
|
||||||
|
doc := formatRuntimeContextForPrompt()
|
||||||
|
if !strings.Contains(strings.ToLower(doc), strings.ToLower(runtime.GOOS)) {
|
||||||
|
t.Fatalf("expected runtime context contains GOOS=%s, got: %s", runtime.GOOS, doc)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package agent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type capabilityRouteDecision struct {
|
||||||
|
NeedSkills bool `json:"need_skills"`
|
||||||
|
SelectedTools []string `json:"selected_tools"`
|
||||||
|
SelectedSkills []string `json:"selected_skills"`
|
||||||
|
Reason string `json:"reason"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseCapabilityRoute(raw string) (capabilityRouteDecision, error) {
|
||||||
|
raw = normalizeJSON(raw)
|
||||||
|
start := strings.Index(raw, "{")
|
||||||
|
end := strings.LastIndex(raw, "}")
|
||||||
|
if start < 0 || end < start {
|
||||||
|
return capabilityRouteDecision{}, fmt.Errorf("no json object found")
|
||||||
|
}
|
||||||
|
raw = raw[start : end+1]
|
||||||
|
|
||||||
|
var out capabilityRouteDecision
|
||||||
|
if err := json.Unmarshal([]byte(raw), &out); err != nil {
|
||||||
|
return capabilityRouteDecision{}, err
|
||||||
|
}
|
||||||
|
out.Reason = strings.TrimSpace(out.Reason)
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package agent
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestParseCapabilityRoute(t *testing.T) {
|
||||||
|
raw := `{"need_skills":true,"selected_tools":["shell"],"selected_skills":["文件系统查询专家"],"reason":"需要技能约束"}`
|
||||||
|
out, err := parseCapabilityRoute(raw)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("parseCapabilityRoute error: %v", err)
|
||||||
|
}
|
||||||
|
if !out.NeedSkills {
|
||||||
|
t.Fatal("expected need_skills=true")
|
||||||
|
}
|
||||||
|
if len(out.SelectedTools) != 1 || out.SelectedTools[0] != "shell" {
|
||||||
|
t.Fatalf("unexpected selected_tools: %#v", out.SelectedTools)
|
||||||
|
}
|
||||||
|
if len(out.SelectedSkills) != 1 || out.SelectedSkills[0] != "文件系统查询专家" {
|
||||||
|
t.Fatalf("unexpected selected_skills: %#v", out.SelectedSkills)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseCapabilityRouteCodeFence(t *testing.T) {
|
||||||
|
raw := "```json\n{\"need_skills\":false,\"selected_tools\":[\"file\",\"shell\"],\"selected_skills\":[],\"reason\":\"工具足够\"}\n```"
|
||||||
|
out, err := parseCapabilityRoute(raw)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("parseCapabilityRoute error: %v", err)
|
||||||
|
}
|
||||||
|
if out.NeedSkills {
|
||||||
|
t.Fatal("expected need_skills=false")
|
||||||
|
}
|
||||||
|
if len(out.SelectedTools) != 2 {
|
||||||
|
t.Fatalf("unexpected selected_tools len: %d", len(out.SelectedTools))
|
||||||
|
}
|
||||||
|
}
|
||||||
+199
-6
@@ -6,6 +6,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -18,6 +19,20 @@ type Client interface {
|
|||||||
Generate(ctx context.Context, systemPrompt, userPrompt string) (string, error)
|
Generate(ctx context.Context, systemPrompt, userPrompt string) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FileChatClient interface {
|
||||||
|
GenerateWithFiles(ctx context.Context, systemPrompt, userPrompt string, fileIDs []string) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileUploader interface {
|
||||||
|
UploadFile(ctx context.Context, file InputFile, purpose string) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type InputFile struct {
|
||||||
|
FileName string
|
||||||
|
MimeType string
|
||||||
|
Content []byte
|
||||||
|
}
|
||||||
|
|
||||||
type OpenAICompatibleClient struct {
|
type OpenAICompatibleClient struct {
|
||||||
baseURL string
|
baseURL string
|
||||||
apiKey string
|
apiKey string
|
||||||
@@ -43,27 +58,64 @@ type chatRequest struct {
|
|||||||
|
|
||||||
type chatMessage struct {
|
type chatMessage struct {
|
||||||
Role string `json:"role"`
|
Role string `json:"role"`
|
||||||
Content string `json:"content"`
|
Content any `json:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type chatContentPart struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Text string `json:"text,omitempty"`
|
||||||
|
FileID string `json:"file_id,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type chatResponse struct {
|
type chatResponse struct {
|
||||||
Choices []struct {
|
Choices []struct {
|
||||||
Message chatMessage `json:"message"`
|
Message struct {
|
||||||
|
Role string `json:"role"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
} `json:"message"`
|
||||||
} `json:"choices"`
|
} `json:"choices"`
|
||||||
Error *struct {
|
Error *struct {
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
} `json:"error,omitempty"`
|
} `json:"error,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *OpenAICompatibleClient) Generate(ctx context.Context, systemPrompt, userPrompt string) (string, error) {
|
type fileUploadResponse struct {
|
||||||
if c.log != nil {
|
ID string `json:"id"`
|
||||||
c.log.Debugf("llm request start model=%s system_len=%d user_len=%d", c.model, len(systemPrompt), len(userPrompt))
|
Bytes int64 `json:"bytes,omitempty"`
|
||||||
|
CreatedAt int64 `json:"created_at,omitempty"`
|
||||||
|
Filename string `json:"filename,omitempty"`
|
||||||
|
Object string `json:"object,omitempty"`
|
||||||
|
Purpose string `json:"purpose,omitempty"`
|
||||||
|
Code int `json:"code,omitempty"`
|
||||||
|
Message string `json:"message,omitempty"`
|
||||||
|
Status any `json:"status,omitempty"`
|
||||||
|
StatusDetails any `json:"status_details,omitempty"`
|
||||||
|
Data *struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
} `json:"data,omitempty"`
|
||||||
|
Error *struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
} `json:"error,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *OpenAICompatibleClient) Generate(ctx context.Context, systemPrompt, userPrompt string) (string, error) {
|
||||||
|
return c.generateInternal(ctx, systemPrompt, userPrompt, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *OpenAICompatibleClient) GenerateWithFiles(ctx context.Context, systemPrompt, userPrompt string, fileIDs []string) (string, error) {
|
||||||
|
return c.generateInternal(ctx, systemPrompt, userPrompt, fileIDs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *OpenAICompatibleClient) generateInternal(ctx context.Context, systemPrompt, userPrompt string, fileIDs []string) (string, error) {
|
||||||
|
if c.log != nil {
|
||||||
|
c.log.Debugf("llm request start model=%s system_len=%d user_len=%d file_count=%d", c.model, len(systemPrompt), len(userPrompt), len(fileIDs))
|
||||||
|
}
|
||||||
|
userContent := buildUserContent(userPrompt, fileIDs)
|
||||||
body := chatRequest{
|
body := chatRequest{
|
||||||
Model: c.model,
|
Model: c.model,
|
||||||
Messages: []chatMessage{
|
Messages: []chatMessage{
|
||||||
{Role: "system", Content: systemPrompt},
|
{Role: "system", Content: systemPrompt},
|
||||||
{Role: "user", Content: userPrompt},
|
{Role: "user", Content: userContent},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
b, err := json.Marshal(body)
|
b, err := json.Marshal(body)
|
||||||
@@ -132,3 +184,144 @@ func (c *OpenAICompatibleClient) Generate(ctx context.Context, systemPrompt, use
|
|||||||
|
|
||||||
return out.Choices[0].Message.Content, nil
|
return out.Choices[0].Message.Content, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func buildUserContent(userPrompt string, fileIDs []string) any {
|
||||||
|
trimmedPrompt := strings.TrimSpace(userPrompt)
|
||||||
|
if len(fileIDs) == 0 {
|
||||||
|
return userPrompt
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := make([]chatContentPart, 0, len(fileIDs)+1)
|
||||||
|
if trimmedPrompt != "" {
|
||||||
|
parts = append(parts, chatContentPart{Type: "text", Text: userPrompt})
|
||||||
|
}
|
||||||
|
for _, id := range fileIDs {
|
||||||
|
id = strings.TrimSpace(id)
|
||||||
|
if id == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
parts = append(parts, chatContentPart{Type: "file", FileID: id})
|
||||||
|
}
|
||||||
|
if len(parts) == 0 {
|
||||||
|
return userPrompt
|
||||||
|
}
|
||||||
|
return parts
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *OpenAICompatibleClient) UploadFile(ctx context.Context, file InputFile, purpose string) (string, error) {
|
||||||
|
if strings.TrimSpace(file.FileName) == "" {
|
||||||
|
return "", fmt.Errorf("empty file name")
|
||||||
|
}
|
||||||
|
if len(file.Content) == 0 {
|
||||||
|
return "", fmt.Errorf("empty file content")
|
||||||
|
}
|
||||||
|
purpose = strings.TrimSpace(purpose)
|
||||||
|
purposes := []string{}
|
||||||
|
if purpose != "" {
|
||||||
|
purposes = append(purposes, purpose)
|
||||||
|
}
|
||||||
|
// Provider compatibility fallback order.
|
||||||
|
purposes = appendIfMissing(purposes, "file-extract")
|
||||||
|
purposes = appendIfMissing(purposes, "batch")
|
||||||
|
|
||||||
|
var lastErr error
|
||||||
|
for _, p := range purposes {
|
||||||
|
fileID, err := c.uploadFileOnce(ctx, file, p)
|
||||||
|
if err == nil {
|
||||||
|
return fileID, nil
|
||||||
|
}
|
||||||
|
lastErr = err
|
||||||
|
if c.log != nil {
|
||||||
|
c.log.Warnf("llm file upload failed purpose=%s err=%v", p, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if lastErr == nil {
|
||||||
|
lastErr = fmt.Errorf("llm file upload failed: no purpose tried")
|
||||||
|
}
|
||||||
|
return "", lastErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *OpenAICompatibleClient) uploadFileOnce(ctx context.Context, file InputFile, purpose string) (string, error) {
|
||||||
|
|
||||||
|
body := &bytes.Buffer{}
|
||||||
|
writer := multipart.NewWriter(body)
|
||||||
|
if err := writer.WriteField("purpose", purpose); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
part, err := writer.CreateFormFile("file", file.FileName)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if _, err := part.Write(file.Content); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if err := writer.Close(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
url := strings.TrimRight(c.baseURL, "/") + "/files"
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, body)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||||
|
req.Header.Set("Authorization", "Bearer "+c.apiKey)
|
||||||
|
|
||||||
|
resp, err := c.http.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
raw, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var out fileUploadResponse
|
||||||
|
if err := json.Unmarshal(raw, &out); err != nil {
|
||||||
|
return "", fmt.Errorf("llm file upload response decode failed: %w body=%s", err, clipForError(raw))
|
||||||
|
}
|
||||||
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||||
|
if strings.TrimSpace(out.Message) != "" {
|
||||||
|
return "", fmt.Errorf("llm file upload error: %s", out.Message)
|
||||||
|
}
|
||||||
|
if out.Error != nil && out.Error.Message != "" {
|
||||||
|
return "", fmt.Errorf("llm file upload error: %s", out.Error.Message)
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("llm file upload status: %d body=%s", resp.StatusCode, clipForError(raw))
|
||||||
|
}
|
||||||
|
fileID := strings.TrimSpace(out.ID)
|
||||||
|
if fileID == "" && out.Data != nil {
|
||||||
|
fileID = strings.TrimSpace(out.Data.ID)
|
||||||
|
}
|
||||||
|
if fileID == "" {
|
||||||
|
return "", fmt.Errorf("llm file upload returned empty file id body=%s", clipForError(raw))
|
||||||
|
}
|
||||||
|
if c.log != nil {
|
||||||
|
c.log.Infof("llm file uploaded name=%s size=%d file_id=%s purpose=%s status=%v", file.FileName, len(file.Content), fileID, purpose, out.Status)
|
||||||
|
}
|
||||||
|
return fileID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func clipForError(raw []byte) string {
|
||||||
|
s := strings.TrimSpace(string(raw))
|
||||||
|
const max = 400
|
||||||
|
if len(s) <= max {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return s[:max] + "...(truncated)"
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendIfMissing(items []string, value string) []string {
|
||||||
|
value = strings.TrimSpace(value)
|
||||||
|
if value == "" {
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
for _, it := range items {
|
||||||
|
if strings.EqualFold(strings.TrimSpace(it), value) {
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return append(items, value)
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"laodingbot/internal/logger"
|
"laodingbot/internal/logger"
|
||||||
"laodingbot/internal/tools"
|
"laodingbot/internal/tools"
|
||||||
"laodingbot/tools/fileoperation"
|
"laodingbot/tools/fileoperation"
|
||||||
|
"laodingbot/tools/git"
|
||||||
"laodingbot/tools/shell"
|
"laodingbot/tools/shell"
|
||||||
"laodingbot/tools/websearch"
|
"laodingbot/tools/websearch"
|
||||||
)
|
)
|
||||||
@@ -16,6 +17,7 @@ import (
|
|||||||
func RunChild(ctx context.Context, cfg config.Config, log *logger.Logger) error {
|
func RunChild(ctx context.Context, cfg config.Config, log *logger.Logger) error {
|
||||||
var registryLog *logger.Logger
|
var registryLog *logger.Logger
|
||||||
var fileLog *logger.Logger
|
var fileLog *logger.Logger
|
||||||
|
var gitLog *logger.Logger
|
||||||
var shellLog *logger.Logger
|
var shellLog *logger.Logger
|
||||||
var searchLog *logger.Logger
|
var searchLog *logger.Logger
|
||||||
var serverLog *logger.Logger
|
var serverLog *logger.Logger
|
||||||
@@ -23,12 +25,19 @@ func RunChild(ctx context.Context, cfg config.Config, log *logger.Logger) error
|
|||||||
log.Infof("toolhost child starting")
|
log.Infof("toolhost child starting")
|
||||||
registryLog = log.WithComponent("toolhost.registry")
|
registryLog = log.WithComponent("toolhost.registry")
|
||||||
fileLog = log.WithComponent("toolhost.file")
|
fileLog = log.WithComponent("toolhost.file")
|
||||||
|
gitLog = log.WithComponent("toolhost.git")
|
||||||
shellLog = log.WithComponent("toolhost.shell")
|
shellLog = log.WithComponent("toolhost.shell")
|
||||||
searchLog = log.WithComponent("toolhost.websearch")
|
searchLog = log.WithComponent("toolhost.websearch")
|
||||||
serverLog = log.WithComponent("toolhost.server")
|
serverLog = log.WithComponent("toolhost.server")
|
||||||
}
|
}
|
||||||
registry := tools.NewRegistry(registryLog)
|
registry := tools.NewRegistry(registryLog)
|
||||||
registry.Register(fileoperation.New(cfg.Security.AllowedDirs, cfg.ToolOutputMaxChars, fileLog))
|
registry.Register(fileoperation.New(cfg.Security.AllowedDirs, cfg.ToolOutputMaxChars, fileLog))
|
||||||
|
registry.Register(git.New(
|
||||||
|
cfg.Security.WorkDir,
|
||||||
|
time.Duration(cfg.ToolCallTimeoutSec)*time.Second,
|
||||||
|
cfg.ToolOutputMaxChars,
|
||||||
|
gitLog,
|
||||||
|
))
|
||||||
registry.Register(shell.New(
|
registry.Register(shell.New(
|
||||||
cfg.Security.AllowedCommands,
|
cfg.Security.AllowedCommands,
|
||||||
cfg.Security.WorkDir,
|
cfg.Security.WorkDir,
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"mime"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -34,9 +38,17 @@ type IncomingMessage struct {
|
|||||||
MessageID string
|
MessageID string
|
||||||
ChatID string
|
ChatID string
|
||||||
UserID string
|
UserID string
|
||||||
|
MsgType string
|
||||||
Text string
|
Text string
|
||||||
|
FileName string
|
||||||
|
FileKey string
|
||||||
|
FileMime string
|
||||||
|
FileBytes []byte
|
||||||
|
FilePath string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const maxFeishuFileBytes = 20 * 1024 * 1024
|
||||||
|
|
||||||
func NewBot(appID, appSecret, verifyToken, _ string, _ string, log *logger.Logger) (*Bot, error) {
|
func NewBot(appID, appSecret, verifyToken, _ string, _ string, log *logger.Logger) (*Bot, error) {
|
||||||
if appID == "" || appSecret == "" {
|
if appID == "" || appSecret == "" {
|
||||||
return nil, fmt.Errorf("empty feishu app credentials")
|
return nil, fmt.Errorf("empty feishu app credentials")
|
||||||
@@ -66,7 +78,7 @@ func (b *Bot) Run(ctx context.Context, handler func(context.Context, IncomingMes
|
|||||||
incoming, ok := parseIncoming(event)
|
incoming, ok := parseIncoming(event)
|
||||||
if !ok {
|
if !ok {
|
||||||
if b.log != nil {
|
if b.log != nil {
|
||||||
b.log.Debugf("skip non-text or invalid feishu event")
|
b.log.Debugf("skip unsupported or invalid feishu event")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -76,8 +88,11 @@ func (b *Bot) Run(ctx context.Context, handler func(context.Context, IncomingMes
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
if incoming.MsgType == "file" {
|
||||||
|
b.enrichFileIncoming(evtCtx, &incoming)
|
||||||
|
}
|
||||||
if b.log != nil {
|
if b.log != nil {
|
||||||
b.log.Infof("feishu message received message_id=%s chat_id=%s user_id=%s text=%s", incoming.MessageID, incoming.ChatID, incoming.UserID, incoming.Text)
|
b.log.Infof("feishu message received message_id=%s chat_id=%s user_id=%s msg_type=%s text=%s", incoming.MessageID, incoming.ChatID, incoming.UserID, incoming.MsgType, incoming.Text)
|
||||||
}
|
}
|
||||||
reply, err := handler(evtCtx, incoming)
|
reply, err := handler(evtCtx, incoming)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -159,6 +174,175 @@ func extractText(content string) (string, error) {
|
|||||||
return parsed.Text, nil
|
return parsed.Text, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func extractFileMeta(content string) (fileName string, fileKey string, err error) {
|
||||||
|
var parsed map[string]any
|
||||||
|
if err := json.Unmarshal([]byte(content), &parsed); err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
readString := func(keys ...string) string {
|
||||||
|
for _, key := range keys {
|
||||||
|
if v, ok := parsed[key]; ok {
|
||||||
|
s, ok := v.(string)
|
||||||
|
if ok {
|
||||||
|
trimmed := strings.TrimSpace(s)
|
||||||
|
if trimmed != "" {
|
||||||
|
return trimmed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
fileName = readString("file_name", "fileName", "name", "filename")
|
||||||
|
fileKey = readString("file_key", "fileKey", "key")
|
||||||
|
return fileName, fileKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildFileRecognitionText(fileName, fileKey string) string {
|
||||||
|
if strings.TrimSpace(fileName) == "" {
|
||||||
|
fileName = "(unknown)"
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(fileKey) == "" {
|
||||||
|
fileKey = "(unknown)"
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join([]string{
|
||||||
|
"用户发送了一条飞书文件消息。",
|
||||||
|
"文件名: " + fileName,
|
||||||
|
"文件Key: " + fileKey,
|
||||||
|
"系统将先上传该文件到 LLM Provider,再由模型完成文档解析。若上传失败,本次请求将直接中止。",
|
||||||
|
}, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bot) enrichFileIncoming(ctx context.Context, incoming *IncomingMessage) {
|
||||||
|
if incoming == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(incoming.MessageID) == "" || strings.TrimSpace(incoming.FileKey) == "" {
|
||||||
|
incoming.Text = buildFileRecognitionText(incoming.FileName, incoming.FileKey)
|
||||||
|
incoming.Text += "\n\n未找到完整 file_key 或 message_id,暂时无法下载文件内容。"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
content, fileName, err := b.downloadFileContent(ctx, incoming.MessageID, incoming.FileKey)
|
||||||
|
if err != nil {
|
||||||
|
if b.log != nil {
|
||||||
|
b.log.Warnf("feishu download file content failed message_id=%s file_key=%s err=%v", incoming.MessageID, incoming.FileKey, err)
|
||||||
|
}
|
||||||
|
incoming.Text = buildFileRecognitionText(incoming.FileName, incoming.FileKey)
|
||||||
|
incoming.Text += "\n\n文件下载失败: " + err.Error()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(fileName) != "" {
|
||||||
|
incoming.FileName = fileName
|
||||||
|
}
|
||||||
|
incoming.FileBytes = content
|
||||||
|
incoming.FileMime = detectMimeByName(incoming.FileName)
|
||||||
|
localPath, saveErr := saveIncomingFile("files", incoming.FileName, incoming.FileBytes)
|
||||||
|
if saveErr != nil {
|
||||||
|
if b.log != nil {
|
||||||
|
b.log.Warnf("save incoming feishu file failed name=%s err=%v", incoming.FileName, saveErr)
|
||||||
|
}
|
||||||
|
incoming.Text = buildFileRecognitionText(incoming.FileName, incoming.FileKey)
|
||||||
|
incoming.Text += "\n\n文件已下载但本地保存失败: " + saveErr.Error()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
incoming.FilePath = localPath
|
||||||
|
incoming.Text = buildFileRecognitionText(incoming.FileName, incoming.FileKey)
|
||||||
|
incoming.Text += fmt.Sprintf("\n\n文件已下载并保存到本地,路径=%s,大小=%d bytes,mime=%s。", incoming.FilePath, len(content), incoming.FileMime)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bot) downloadFileContent(ctx context.Context, messageID, fileKey string) ([]byte, string, error) {
|
||||||
|
req := larkim.NewGetMessageResourceReqBuilder().
|
||||||
|
MessageId(messageID).
|
||||||
|
FileKey(fileKey).
|
||||||
|
Type("file").
|
||||||
|
Build()
|
||||||
|
|
||||||
|
resp, err := b.apiClient.Im.MessageResource.Get(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
if resp == nil || resp.File == nil {
|
||||||
|
if resp != nil {
|
||||||
|
return nil, "", fmt.Errorf("empty file stream code=%d msg=%s", resp.Code, resp.Msg)
|
||||||
|
}
|
||||||
|
return nil, "", fmt.Errorf("empty file stream")
|
||||||
|
}
|
||||||
|
|
||||||
|
bts, err := io.ReadAll(resp.File)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
if len(bts) > maxFeishuFileBytes {
|
||||||
|
return nil, "", fmt.Errorf("file too large: %d bytes, max=%d", len(bts), maxFeishuFileBytes)
|
||||||
|
}
|
||||||
|
return bts, strings.TrimSpace(resp.FileName), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectMimeByName(fileName string) string {
|
||||||
|
ext := strings.ToLower(strings.TrimSpace(filepath.Ext(fileName)))
|
||||||
|
if ext == "" {
|
||||||
|
return "application/octet-stream"
|
||||||
|
}
|
||||||
|
m := strings.TrimSpace(mime.TypeByExtension(ext))
|
||||||
|
if m == "" {
|
||||||
|
return "application/octet-stream"
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveIncomingFile(baseDir, fileName string, content []byte) (string, error) {
|
||||||
|
if len(content) == 0 {
|
||||||
|
return "", fmt.Errorf("empty file content")
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(baseDir) == "" {
|
||||||
|
baseDir = "files"
|
||||||
|
}
|
||||||
|
if err := os.MkdirAll(baseDir, 0o755); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
safeName := sanitizeFileName(fileName)
|
||||||
|
if safeName == "" {
|
||||||
|
safeName = "upload.bin"
|
||||||
|
}
|
||||||
|
finalName := fmt.Sprintf("%d_%s", time.Now().UnixNano(), safeName)
|
||||||
|
target := filepath.Join(baseDir, finalName)
|
||||||
|
if err := os.WriteFile(target, content, 0o644); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
abs, err := filepath.Abs(target)
|
||||||
|
if err != nil {
|
||||||
|
return target, nil
|
||||||
|
}
|
||||||
|
return abs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func sanitizeFileName(fileName string) string {
|
||||||
|
name := strings.TrimSpace(filepath.Base(fileName))
|
||||||
|
if name == "" || name == "." || name == ".." {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
var b strings.Builder
|
||||||
|
for _, r := range name {
|
||||||
|
if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') || r == '.' || r == '_' || r == '-' {
|
||||||
|
b.WriteRune(r)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
b.WriteByte('_')
|
||||||
|
}
|
||||||
|
out := strings.TrimSpace(b.String())
|
||||||
|
if out == "" || out == "." || out == ".." {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(out, ".") {
|
||||||
|
out = "file" + out
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
func parseIncoming(event *larkim.P2MessageReceiveV1) (IncomingMessage, bool) {
|
func parseIncoming(event *larkim.P2MessageReceiveV1) (IncomingMessage, bool) {
|
||||||
if event == nil || event.Event == nil || event.Event.Message == nil || event.Event.Sender == nil || event.Event.Sender.SenderId == nil {
|
if event == nil || event.Event == nil || event.Event.Message == nil || event.Event.Sender == nil || event.Event.Sender.SenderId == nil {
|
||||||
return IncomingMessage{}, false
|
return IncomingMessage{}, false
|
||||||
@@ -168,12 +352,11 @@ func parseIncoming(event *larkim.P2MessageReceiveV1) (IncomingMessage, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
msg := event.Event.Message
|
msg := event.Event.Message
|
||||||
if msg.MessageType == nil || *msg.MessageType != "text" || msg.ChatId == nil || msg.Content == nil || msg.MessageId == nil {
|
if msg.MessageType == nil || msg.ChatId == nil || msg.Content == nil || msg.MessageId == nil {
|
||||||
return IncomingMessage{}, false
|
return IncomingMessage{}, false
|
||||||
}
|
}
|
||||||
|
msgType := strings.TrimSpace(*msg.MessageType)
|
||||||
text, err := extractText(*msg.Content)
|
if msgType == "" {
|
||||||
if err != nil {
|
|
||||||
return IncomingMessage{}, false
|
return IncomingMessage{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,12 +369,33 @@ func parseIncoming(event *larkim.P2MessageReceiveV1) (IncomingMessage, bool) {
|
|||||||
userID = *event.Event.Sender.SenderId.UnionId
|
userID = *event.Event.Sender.SenderId.UnionId
|
||||||
}
|
}
|
||||||
|
|
||||||
return IncomingMessage{
|
incoming := IncomingMessage{
|
||||||
MessageID: *msg.MessageId,
|
MessageID: *msg.MessageId,
|
||||||
ChatID: *msg.ChatId,
|
ChatID: *msg.ChatId,
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
Text: text,
|
MsgType: msgType,
|
||||||
}, true
|
}
|
||||||
|
|
||||||
|
switch msgType {
|
||||||
|
case "text":
|
||||||
|
text, err := extractText(*msg.Content)
|
||||||
|
if err != nil {
|
||||||
|
return IncomingMessage{}, false
|
||||||
|
}
|
||||||
|
incoming.Text = text
|
||||||
|
return incoming, true
|
||||||
|
case "file":
|
||||||
|
fileName, fileKey, err := extractFileMeta(*msg.Content)
|
||||||
|
if err != nil {
|
||||||
|
return IncomingMessage{}, false
|
||||||
|
}
|
||||||
|
incoming.FileName = fileName
|
||||||
|
incoming.FileKey = fileKey
|
||||||
|
incoming.Text = buildFileRecognitionText(fileName, fileKey)
|
||||||
|
return incoming, true
|
||||||
|
default:
|
||||||
|
return IncomingMessage{}, false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bot) shouldProcessMessage(messageID string) bool {
|
func (b *Bot) shouldProcessMessage(messageID string) bool {
|
||||||
|
|||||||
@@ -0,0 +1,138 @@
|
|||||||
|
package feishu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
larkim "github.com/larksuite/oapi-sdk-go/v3/service/im/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func mustEventFromJSON(t *testing.T, raw string) *larkim.P2MessageReceiveV1 {
|
||||||
|
t.Helper()
|
||||||
|
var evt larkim.P2MessageReceiveV1
|
||||||
|
if err := json.Unmarshal([]byte(raw), &evt); err != nil {
|
||||||
|
t.Fatalf("unmarshal event json failed: %v", err)
|
||||||
|
}
|
||||||
|
return &evt
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseIncomingText(t *testing.T) {
|
||||||
|
evt := mustEventFromJSON(t, `{
|
||||||
|
"event": {
|
||||||
|
"message": {
|
||||||
|
"message_id": "msg_text_1",
|
||||||
|
"chat_id": "chat_1",
|
||||||
|
"message_type": "text",
|
||||||
|
"content": "{\"text\":\"你好\"}"
|
||||||
|
},
|
||||||
|
"sender": {
|
||||||
|
"sender_type": "user",
|
||||||
|
"sender_id": {"open_id": "u_open_1"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
in, ok := parseIncoming(evt)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("expected text message parse success")
|
||||||
|
}
|
||||||
|
if in.MsgType != "text" {
|
||||||
|
t.Fatalf("expected msg type text, got %s", in.MsgType)
|
||||||
|
}
|
||||||
|
if in.Text != "你好" {
|
||||||
|
t.Fatalf("unexpected text: %q", in.Text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseIncomingFile(t *testing.T) {
|
||||||
|
evt := mustEventFromJSON(t, `{
|
||||||
|
"event": {
|
||||||
|
"message": {
|
||||||
|
"message_id": "msg_file_1",
|
||||||
|
"chat_id": "chat_1",
|
||||||
|
"message_type": "file",
|
||||||
|
"content": "{\"file_key\":\"file_key_123\",\"file_name\":\"report.pdf\"}"
|
||||||
|
},
|
||||||
|
"sender": {
|
||||||
|
"sender_type": "user",
|
||||||
|
"sender_id": {"user_id": "u_id_1"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
in, ok := parseIncoming(evt)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("expected file message parse success")
|
||||||
|
}
|
||||||
|
if in.MsgType != "file" {
|
||||||
|
t.Fatalf("expected msg type file, got %s", in.MsgType)
|
||||||
|
}
|
||||||
|
if in.FileName != "report.pdf" || in.FileKey != "file_key_123" {
|
||||||
|
t.Fatalf("unexpected file meta: name=%q key=%q", in.FileName, in.FileKey)
|
||||||
|
}
|
||||||
|
if !strings.Contains(in.Text, "飞书文件消息") {
|
||||||
|
t.Fatalf("expected synthesized text mentions file message, got: %q", in.Text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseIncomingUnsupportedType(t *testing.T) {
|
||||||
|
evt := mustEventFromJSON(t, `{
|
||||||
|
"event": {
|
||||||
|
"message": {
|
||||||
|
"message_id": "msg_image_1",
|
||||||
|
"chat_id": "chat_1",
|
||||||
|
"message_type": "image",
|
||||||
|
"content": "{\"image_key\":\"img_1\"}"
|
||||||
|
},
|
||||||
|
"sender": {
|
||||||
|
"sender_type": "user",
|
||||||
|
"sender_id": {"open_id": "u_open_1"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
_, ok := parseIncoming(evt)
|
||||||
|
if ok {
|
||||||
|
t.Fatal("expected unsupported message type rejected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDetectMimeByName(t *testing.T) {
|
||||||
|
if got := detectMimeByName("report.pdf"); !strings.Contains(got, "pdf") {
|
||||||
|
t.Fatalf("expected pdf mime, got: %s", got)
|
||||||
|
}
|
||||||
|
if got := detectMimeByName("unknown.custom"); got != "application/octet-stream" {
|
||||||
|
t.Fatalf("expected octet-stream fallback, got: %s", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSaveIncomingFile(t *testing.T) {
|
||||||
|
dir := t.TempDir()
|
||||||
|
path, err := saveIncomingFile(dir, "report.pdf", []byte("hello"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("saveIncomingFile error: %v", err)
|
||||||
|
}
|
||||||
|
b, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("read saved file failed: %v", err)
|
||||||
|
}
|
||||||
|
if string(b) != "hello" {
|
||||||
|
t.Fatalf("unexpected saved content: %q", string(b))
|
||||||
|
}
|
||||||
|
if filepath.Ext(path) != ".pdf" {
|
||||||
|
t.Fatalf("expected .pdf extension, got: %s", path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSanitizeFileName(t *testing.T) {
|
||||||
|
got := sanitizeFileName("../bad path/测 试?.pdf")
|
||||||
|
if strings.Contains(got, "/") || strings.Contains(got, "\\") {
|
||||||
|
t.Fatalf("expected sanitized basename only, got: %q", got)
|
||||||
|
}
|
||||||
|
if !strings.HasSuffix(got, ".pdf") {
|
||||||
|
t.Fatalf("expected .pdf suffix, got: %q", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
name: architecture-wbs-breakdown
|
||||||
|
description: 作为架构师,将复杂需求拆解为多团队 WBS 详细文档,并自动提交至 Git 仓库
|
||||||
|
---
|
||||||
|
|
||||||
|
# 复杂系统需求拆解与多团队 WBS 规划
|
||||||
|
|
||||||
|
## 使用场景
|
||||||
|
当接收到业务需求文档,需要进行工程化拆解并进行版本化归档时使用,例如:
|
||||||
|
|
||||||
|
- 将单体需求拆解为适合多团队并行开发的 SAFe/PI 规划 WBS
|
||||||
|
- 界定系统中不同子系统(或软硬件团队)的交互边界与契约
|
||||||
|
- 将生成的拆解报告自动化落地并推送到远程代码仓库
|
||||||
|
|
||||||
|
## 架构拆分与团队规划
|
||||||
|
- 提取核心业务流程与全局非功能性需求 (NFR)
|
||||||
|
- 运用限界上下文划分独立演进的子系统,明确交互契约(API、RPC、ICD 等)
|
||||||
|
- 为每个子系统配置专属开发团队,定义角色配置(SM, PO, 开发, 测试)
|
||||||
|
|
||||||
|
## WBS 拆解与输出约束
|
||||||
|
- 按 Epic -> Feature -> Story/Task 的敏捷层级,输出结构清晰、详细的 Markdown 文档
|
||||||
|
- 明确跨团队的交付物契约,梳理 Feature 依赖关系以识别集成风险点
|
||||||
|
|
||||||
|
## 文档归档与版本控制 (工作流执行)
|
||||||
|
文档生成完毕后,必须触发以下自动化流程:
|
||||||
|
- **文件保存**:将生成的 Markdown 文档以合适的命名(如 `wbs_规划_[日期].md`)写入本地的 `new_floder` 文件夹中。
|
||||||
|
- **版本追踪**:使用 Git 管理该文件夹,执行 `git add .`(或指定该 md 文件)。
|
||||||
|
- **提交变更**:生成准确的提交信息(例如 `docs: add WBS breakdown for [项目/需求简述]`),执行 `git commit`。
|
||||||
|
- **远程同步**:将本地提交推送到远程 Git 仓库,执行 `git push`。
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
package git
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"laodingbot/internal/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Tool provides common Git operations through a safe command whitelist.
|
||||||
|
type Tool struct {
|
||||||
|
repoDir string
|
||||||
|
allowedSubcmds map[string]struct{}
|
||||||
|
timeout time.Duration
|
||||||
|
maxOutputChars int
|
||||||
|
log *logger.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new git tool.
|
||||||
|
func New(repoDir string, timeout time.Duration, maxOutputChars int, log *logger.Logger) *Tool {
|
||||||
|
absRepo, err := filepath.Abs(strings.TrimSpace(repoDir))
|
||||||
|
if err != nil {
|
||||||
|
absRepo = strings.TrimSpace(repoDir)
|
||||||
|
}
|
||||||
|
if timeout <= 0 {
|
||||||
|
timeout = 20 * time.Second
|
||||||
|
}
|
||||||
|
if maxOutputChars <= 0 {
|
||||||
|
maxOutputChars = 4000
|
||||||
|
}
|
||||||
|
|
||||||
|
allowed := map[string]struct{}{
|
||||||
|
"status": {},
|
||||||
|
"log": {},
|
||||||
|
"show": {},
|
||||||
|
"diff": {},
|
||||||
|
"branch": {},
|
||||||
|
"checkout": {},
|
||||||
|
"switch": {},
|
||||||
|
"restore": {},
|
||||||
|
"add": {},
|
||||||
|
"commit": {},
|
||||||
|
"reset": {},
|
||||||
|
"revert": {},
|
||||||
|
"merge": {},
|
||||||
|
"rebase": {},
|
||||||
|
"cherry-pick": {},
|
||||||
|
"fetch": {},
|
||||||
|
"pull": {},
|
||||||
|
"push": {},
|
||||||
|
"remote": {},
|
||||||
|
"tag": {},
|
||||||
|
"stash": {},
|
||||||
|
"blame": {},
|
||||||
|
"rev-parse": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
if log != nil {
|
||||||
|
log.Infof("git tool initialized repo_dir=%s timeout=%s max_output_chars=%d", absRepo, timeout, maxOutputChars)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Tool{
|
||||||
|
repoDir: absRepo,
|
||||||
|
allowedSubcmds: allowed,
|
||||||
|
timeout: timeout,
|
||||||
|
maxOutputChars: maxOutputChars,
|
||||||
|
log: log,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Tool) Name() string { return "git" }
|
||||||
|
|
||||||
|
func (t *Tool) Description() string {
|
||||||
|
return "Run common git commands inside repository. Input examples: status --short | log --oneline -n 10 | add . | commit -m fix | branch"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Tool) Call(ctx context.Context, input string) (string, error) {
|
||||||
|
trimmed := strings.TrimSpace(input)
|
||||||
|
if trimmed == "" {
|
||||||
|
if t.log != nil {
|
||||||
|
t.log.Warnf("git tool rejected empty command")
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("empty git command")
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.Fields(trimmed)
|
||||||
|
if len(parts) == 0 {
|
||||||
|
return "", fmt.Errorf("empty git command")
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.EqualFold(parts[0], "git") {
|
||||||
|
parts = parts[1:]
|
||||||
|
}
|
||||||
|
if len(parts) == 0 {
|
||||||
|
return "", fmt.Errorf("missing git subcommand")
|
||||||
|
}
|
||||||
|
|
||||||
|
subcmd := strings.ToLower(parts[0])
|
||||||
|
if _, ok := t.allowedSubcmds[subcmd]; !ok {
|
||||||
|
if t.log != nil {
|
||||||
|
t.log.Warnf("git tool rejected subcommand=%s", subcmd)
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("unsupported git subcommand: %s", subcmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
runCtx, cancel := context.WithTimeout(ctx, t.timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
args := append([]string{subcmd}, parts[1:]...)
|
||||||
|
if t.log != nil {
|
||||||
|
t.log.Infof("git command start subcommand=%s args=%d full=%q", subcmd, len(parts)-1, strings.Join(args, " "))
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.CommandContext(runCtx, "git", args...)
|
||||||
|
cmd.Dir = t.repoDir
|
||||||
|
cmd.Env = append(cmd.Environ(),
|
||||||
|
"GIT_TERMINAL_PROMPT=0",
|
||||||
|
"GIT_PAGER=cat",
|
||||||
|
"GIT_EDITOR=true",
|
||||||
|
)
|
||||||
|
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
outText := strings.TrimSpace(string(out))
|
||||||
|
if len(outText) > t.maxOutputChars {
|
||||||
|
outText = outText[:t.maxOutputChars]
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if t.log != nil {
|
||||||
|
t.log.Errorf("git command failed subcommand=%s err=%v output=%q", subcmd, err, outText)
|
||||||
|
}
|
||||||
|
if outText == "" {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return outText, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.log != nil {
|
||||||
|
t.log.Infof("git command success subcommand=%s output_bytes=%d", subcmd, len(out))
|
||||||
|
}
|
||||||
|
if outText == "" {
|
||||||
|
return "ok", nil
|
||||||
|
}
|
||||||
|
return outText, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
package git
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCallRejectsEmptyCommand(t *testing.T) {
|
||||||
|
tool := New(t.TempDir(), 3*time.Second, 4000, nil)
|
||||||
|
_, err := tool.Call(context.Background(), " ")
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected error for empty command")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCallRejectsUnsupportedSubcommand(t *testing.T) {
|
||||||
|
repo := initTestRepo(t)
|
||||||
|
tool := New(repo, 5*time.Second, 4000, nil)
|
||||||
|
|
||||||
|
_, err := tool.Call(context.Background(), "bisect start")
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected unsupported subcommand error")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), "unsupported git subcommand") {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStatusAndLog(t *testing.T) {
|
||||||
|
repo := initTestRepo(t)
|
||||||
|
tool := New(repo, 5*time.Second, 4000, nil)
|
||||||
|
|
||||||
|
status, err := tool.Call(context.Background(), "status --short")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("status failed: %v", err)
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(status) != "" && status != "ok" {
|
||||||
|
t.Fatalf("expected clean status output, got: %q", status)
|
||||||
|
}
|
||||||
|
|
||||||
|
logOut, err := tool.Call(context.Background(), "git log --oneline -n 1")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("log failed: %v", err)
|
||||||
|
}
|
||||||
|
if !strings.Contains(logOut, "initial commit") {
|
||||||
|
t.Fatalf("expected initial commit in log output, got: %q", logOut)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddCommitAndDiff(t *testing.T) {
|
||||||
|
repo := initTestRepo(t)
|
||||||
|
tool := New(repo, 8*time.Second, 8000, nil)
|
||||||
|
|
||||||
|
file := filepath.Join(repo, "note.txt")
|
||||||
|
if err := os.WriteFile(file, []byte("v1\n"), 0o644); err != nil {
|
||||||
|
t.Fatalf("write file failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := tool.Call(context.Background(), "add note.txt")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("add failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = tool.Call(context.Background(), "commit -m add-note")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("commit failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.WriteFile(file, []byte("v2\n"), 0o644); err != nil {
|
||||||
|
t.Fatalf("rewrite file failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
diffOut, err := tool.Call(context.Background(), "diff -- note.txt")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("diff failed: %v", err)
|
||||||
|
}
|
||||||
|
if !strings.Contains(diffOut, "-v1") || !strings.Contains(diffOut, "+v2") {
|
||||||
|
t.Fatalf("expected diff output with v1/v2 changes, got: %q", diffOut)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func initTestRepo(t *testing.T) string {
|
||||||
|
t.Helper()
|
||||||
|
if _, err := exec.LookPath("git"); err != nil {
|
||||||
|
t.Skip("git is not installed")
|
||||||
|
}
|
||||||
|
|
||||||
|
repo := t.TempDir()
|
||||||
|
runGit(t, repo, "init")
|
||||||
|
runGit(t, repo, "config", "user.name", "test-user")
|
||||||
|
runGit(t, repo, "config", "user.email", "test@example.com")
|
||||||
|
|
||||||
|
readme := filepath.Join(repo, "README.md")
|
||||||
|
if err := os.WriteFile(readme, []byte("hello\n"), 0o644); err != nil {
|
||||||
|
t.Fatalf("write readme failed: %v", err)
|
||||||
|
}
|
||||||
|
runGit(t, repo, "add", "README.md")
|
||||||
|
runGit(t, repo, "commit", "-m", "initial commit")
|
||||||
|
|
||||||
|
return repo
|
||||||
|
}
|
||||||
|
|
||||||
|
func runGit(t *testing.T, repo string, args ...string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
cmd := exec.CommandContext(ctx, "git", args...)
|
||||||
|
cmd.Dir = repo
|
||||||
|
cmd.Env = append(cmd.Environ(),
|
||||||
|
"GIT_TERMINAL_PROMPT=0",
|
||||||
|
"GIT_PAGER=cat",
|
||||||
|
"GIT_EDITOR=true",
|
||||||
|
)
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
// Keep default behavior; this branch documents cross-platform intent.
|
||||||
|
}
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("git %s failed: %v\n%s", strings.Join(args, " "), err, string(out))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -94,6 +94,9 @@ func (t *Tool) Call(ctx context.Context, input string) (string, error) {
|
|||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
// Windows 下使用 cmd /C 执行,兼容 date、dir 等内建命令。
|
// Windows 下使用 cmd /C 执行,兼容 date、dir 等内建命令。
|
||||||
cmd = exec.CommandContext(runCtx, "cmd", "/C", trimmed)
|
cmd = exec.CommandContext(runCtx, "cmd", "/C", trimmed)
|
||||||
|
} else if requiresShellParsing(trimmed) {
|
||||||
|
// 包含管道、重定向等语法时,必须交给 shell 解释。
|
||||||
|
cmd = exec.CommandContext(runCtx, "sh", "-c", trimmed)
|
||||||
} else {
|
} else {
|
||||||
cmd = exec.CommandContext(runCtx, base, parts[1:]...)
|
cmd = exec.CommandContext(runCtx, base, parts[1:]...)
|
||||||
}
|
}
|
||||||
@@ -126,3 +129,7 @@ func normalizeWindowsCommand(command string) string {
|
|||||||
return command
|
return command
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func requiresShellParsing(command string) bool {
|
||||||
|
return strings.ContainsAny(command, "|&;<>()$`\\\n")
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,3 +40,27 @@ func TestCallWindowsDateIsNonInteractive(t *testing.T) {
|
|||||||
t.Fatal("expected non-empty output for date command")
|
t.Fatal("expected non-empty output for date command")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRequiresShellParsing(t *testing.T) {
|
||||||
|
if !requiresShellParsing("echo hi | cat") {
|
||||||
|
t.Fatal("expected pipe command to require shell parsing")
|
||||||
|
}
|
||||||
|
if requiresShellParsing("echo hello") {
|
||||||
|
t.Fatal("expected simple command to not require shell parsing")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCallSupportsPipeOnUnix(t *testing.T) {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
t.Skip("unix-only behavior test")
|
||||||
|
}
|
||||||
|
tool := New([]string{"echo"}, ".", 3*time.Second, 4000, nil)
|
||||||
|
out, err := tool.Call(context.Background(), "printf hello | wc -c")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected pipeline command success, got err=%v output=%q", err, out)
|
||||||
|
}
|
||||||
|
trimmed := strings.TrimSpace(out)
|
||||||
|
if trimmed != "5" {
|
||||||
|
t.Fatalf("expected output 5, got %q", trimmed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user